Есть ли какие-либо платформы, где указатели на различные типы имеют различные размеры?

Хотя это древний вопрос, а 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. В обоих случаях я двигал мышь примерно с одинаковой скоростью.

enter image description here

57
задан Adam Rosenfield 31 October 2017 в 20:18
поделиться

7 ответов

Ответ из C FAQ :

Серия 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 бит для обозначения байтовый адрес в слове.

Дополнительные ссылки: сообщение от Криса Торека с более подробной информацией о некоторых из этих машин.

46
ответ дан 24 November 2019 в 19:30
поделиться

Не совсем то, о чем вы спрашиваете, но во времена 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

28
ответ дан 24 November 2019 в 19:30
поделиться

Следовательно, логически следует, что sizeof (void *)> = sizeof (T *) для всех типов T, верно?

Это не обязательно следует , поскольку sizeof относится к представлению хранилища, и не все битовые шаблоны должны быть допустимыми значениями. Я думаю, вы могли бы написать соответствующую реализацию, где sizeof (int *) == 8 , sizeof (void *) == 4 , но существует не более 2 ^ 32 возможных значений для int *. Не знаю, зачем вам это нужно.

13
ответ дан 24 November 2019 в 19:30
поделиться

В золотые годы DOS, 8088-х и сегментированной памяти было принято указывать «модель памяти», в которой, например, весь код умещался в 64 КБ (один сегмент), но данные могли охватывать несколько сегментов; это означало, что указатель функции будет 2 байта, указатель данных - 4 байта. Не уверен, что кто-то все еще занимается программированием для машин такого типа, возможно, некоторые еще выживают во встроенных системах.

11
ответ дан 24 November 2019 в 19:30
поделиться

Можно легко представить себе машину с архитектурой Гарварда, имеющую разные размеры для указателей функций и всех других указателей. Не знаю примера ...

7
ответ дан 24 November 2019 в 19:30
поделиться

Ближайшие и дальние указатели все еще используются на некоторых встроенных микроконтроллерах со страничной флэш-памятью или ОЗУ, чтобы вы могли указывать на данные на той же странице (ближний указатель) или другой странице (дальний указатель, который больше, поскольку включает информацию о странице).

Например, микроконтроллер Freescale HCS12 использует 16-битную архитектуру фон Неймана, что означает, что ни один адрес не может быть длиннее 16 бит. Из-за ограничений это приведет к увеличению доступного пространства кода, имеется 8-битный регистр страницы.

Таким образом, чтобы указать данные в той же кодовой странице, вы просто указываете 16-битный адрес; это ближний указатель.

Чтобы указать на данные в другой кодовой странице, вы должны включить в эту страницу как 8-битный номер страницы, так и 16-битный адрес, в результате чего получится 24-битный дальний указатель.

7
ответ дан 24 November 2019 в 19:30
поделиться

Возможно, что размер указателей на данные отличается от размеров указателей, например, на функции. Такое часто случается в микропроцессорах для встроенных систем. В машинах с гарвардской архитектурой, о которых говорил dmckee, это происходит легко.

Получается, что это делает бэкенды gcc мучением для разработки! :)

Edit: Я не могу вдаваться в подробности конкретной машины, о которой я говорю, но позвольте мне добавить, почему машины с гарвардской архитектурой позволяют это легко сделать. Гарвардская архитектура имеет разные хранилища и пути для инструкций и данных, поэтому если шина для инструкций "больше", чем шина для данных, у вас обязательно будет указатель на функцию, размер которого больше, чем указатель на данные!

6
ответ дан 24 November 2019 в 19:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: