Хотя это древний вопрос, а WinForms - это древний фреймворк, я хотел бы поделиться тем, что я только что обнаружил случайно: рисование растрового изображения в BufferedGraphics и его последующее отображение в графическом контексте, предоставляемом OnPaint, представляет собой способ быстрее рисования растрового изображения непосредственно в графическом контексте OnPaint - по крайней мере, на моем компьютере с Windows 10.
Это удивительно, потому что интуитивно я предполагал, что копирование данных будет несколько медленнее (и поэтому я подумал, что это обычно оправдано только тогда, когда кто-то хочет делать двойную буферизацию вручную). Но очевидно, что с объектом BufferedGraphics происходит нечто более сложное.
Поэтому создайте BufferedGraphics в конструкторе элемента управления, который будет содержать растровое изображение (в моем случае я хотел нарисовать полноэкранное растровое изображение 1920x1080):
using (Graphics graphics = CreateGraphics())
{
graphicsBuffer = BufferedGraphicsManager.Current.Allocate(graphics, new Rectangle(0,0,Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height));
}
и использовать его в OnPaint (при аннулировании OnPaintBackground )
protected override void OnPaintBackground(PaintEventArgs e) {/* just rely on the bitmap to fill the screen */}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = graphicsBuffer.Graphics;
g.DrawImage(someBitmap,0,0,bitmap.Width, bitmap.Height);
graphicsBuffer.Render(e.Graphics);
}
вместо наивного определения
protected override void OnPaintBackground(PaintEventArgs e) {/* just rely on the bitmap to fill the screen */}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawImage(someBitmap,0,0,bitmap.Width, bitmap.Height);
}
См. На следующих скриншотах сравнение частоты результирующего события MouseMove (я реализую очень простой элемент управления рисованием растровых изображений). Вверху находится версия, где растровое изображение рисуется напрямую, в нижней части используется BufferedGraphics. В обоих случаях я двигал мышь примерно с одинаковой скоростью.
Серия Prime 50 использовала сегмент 07777, смещение 0 для нулевого указателя, по крайней мере, для PL / I . Более поздние модели использовали сегмент 0, смещение 0 для нулевых указателей в C, что требовало новых инструкций, таких как TCNP (Test C Null Pointer), очевидно, как подачка ко всему существующему плохо написанному коду C, который делал неверные предположения. Старые машины Prime с адресной адресацией по словам также были известны тем, что требовали больших байтовых указателей (char *), чем указатели слов (int *).
Серия Eclipse MV от Data General имеет три архитектурно поддерживаемых формата указателей (word, байт, и битовые указатели), два из которых используются компиляторами C: байтовые указатели для char * и void * и указатели слов для всего остального. По историческим причинам во время эволюции 32-битной линии MV из 16-битной линии Nova указатели слов и байтовые указатели имели биты смещения, косвенного обращения и защиты кольца в разных местах слова. Передача несоответствующего формата указателя в функцию привела к сбоям защиты. В конце концов, компилятор MV C добавил много параметров совместимости, чтобы попытаться справиться с кодом, в котором были ошибки несоответствия типа указателя.
Некоторые мэйнфреймы Honeywell-Bull используют битовый шаблон 06000 для (внутренних) нулевых указателей.
CDC Cyber 180 Серия имеет 48-битные указатели, состоящие из кольца, сегмента и смещения. Большинство пользователей (в кольце 11) имеют нулевые указатели 0xB00000000000. На старых машинах CDC с дополнением до единицы было обычным делом использовать слово, состоящее только из одного бита, в качестве специального флага для всех видов данных, включая недопустимые адреса.
В старых сериях HP 3000 для байтовых адресов используется другая схема адресации, чем для байтовых адресов. для словесных адресов; поэтому, как и некоторые из вышеперечисленных машин, он использует разные представления для указателей char * и void *, чем для других указателей.
Symbolics Lisp Machine, тэгированная архитектура, даже не имеет обычных числовых указателей; он использует пару (в основном несуществующий дескриптор) как нулевой указатель C.
В зависимости от используемой «модели памяти» процессоры семейства 8086 (ПК поэтому, как и некоторые из вышеперечисленных машин, он использует разные представления для указателей char * и void *, чем для других указателей.
Symbolics Lisp Machine, тэгированная архитектура, даже не имеет обычных числовых указателей; он использует пару (в основном несуществующий дескриптор) как нулевой указатель C.
В зависимости от используемой «модели памяти» процессоры семейства 8086 (ПК поэтому, как и некоторые из вышеперечисленных машин, он использует разные представления для указателей char * и void *, чем для других указателей.
Symbolics Lisp Machine, тэгированная архитектура, даже не имеет обычных числовых указателей; он использует пару (в основном несуществующий дескриптор) как нулевой указатель C.
В зависимости от используемой «модели памяти» процессоры семейства 8086 (ПК совместимые) могут использовать 16-битные указатели данных и 32-битную функцию указатели, или наоборот.
Некоторые 64-битные машины Cray представляют int * в младших 48 битах слово; char * дополнительно использует некоторые из старших 16 бит для обозначения байтовый адрес в слове.
Дополнительные ссылки: сообщение от Криса Торека с более подробной информацией о некоторых из этих машин.
Не совсем то, о чем вы спрашиваете, но во времена 16-битных DOS / Windows у вас действительно было различие между указателем и дальним указателем, причем последний был 32-битным .
Возможно, у меня неправильный синтаксис ...
int *pInt = malloc(sizeof(int));
int far *fpInt = _fmalloc(sizeof(int));
printf("pInt: %d, fpInt: %d\n", sizeof(pInt), sizeof(fpInt));
Вывод:
pInt: 2, fpInt 4
Следовательно, логически следует, что sizeof (void *)> = sizeof (T *)
для всех типов T, верно?
Это не обязательно следует , поскольку sizeof относится к представлению хранилища, и не все битовые шаблоны должны быть допустимыми значениями. Я думаю, вы могли бы написать соответствующую реализацию, где sizeof (int *) == 8
, sizeof (void *) == 4
, но существует не более 2 ^ 32 возможных значений для int *. Не знаю, зачем вам это нужно.
В золотые годы DOS, 8088-х и сегментированной памяти было принято указывать «модель памяти», в которой, например, весь код умещался в 64 КБ (один сегмент), но данные могли охватывать несколько сегментов; это означало, что указатель функции будет 2 байта, указатель данных - 4 байта. Не уверен, что кто-то все еще занимается программированием для машин такого типа, возможно, некоторые еще выживают во встроенных системах.
Можно легко представить себе машину с архитектурой Гарварда, имеющую разные размеры для указателей функций и всех других указателей. Не знаю примера ...
Ближайшие и дальние указатели все еще используются на некоторых встроенных микроконтроллерах со страничной флэш-памятью или ОЗУ, чтобы вы могли указывать на данные на той же странице (ближний указатель) или другой странице (дальний указатель, который больше, поскольку включает информацию о странице).
Например, микроконтроллер Freescale HCS12 использует 16-битную архитектуру фон Неймана, что означает, что ни один адрес не может быть длиннее 16 бит. Из-за ограничений это приведет к увеличению доступного пространства кода, имеется 8-битный регистр страницы.
Таким образом, чтобы указать данные в той же кодовой странице, вы просто указываете 16-битный адрес; это ближний указатель.
Чтобы указать на данные в другой кодовой странице, вы должны включить в эту страницу как 8-битный номер страницы, так и 16-битный адрес, в результате чего получится 24-битный дальний указатель.
Возможно, что размер указателей на данные отличается от размеров указателей, например, на функции. Такое часто случается в микропроцессорах для встроенных систем. В машинах с гарвардской архитектурой, о которых говорил dmckee, это происходит легко.
Получается, что это делает бэкенды gcc мучением для разработки! :)
Edit: Я не могу вдаваться в подробности конкретной машины, о которой я говорю, но позвольте мне добавить, почему машины с гарвардской архитектурой позволяют это легко сделать. Гарвардская архитектура имеет разные хранилища и пути для инструкций и данных, поэтому если шина для инструкций "больше", чем шина для данных, у вас обязательно будет указатель на функцию, размер которого больше, чем указатель на данные!