Подтвердить что ты не робот

Существуют ли платформы, где указатели на разные типы имеют разные размеры?

Стандарт C позволяет указателям на разные типы иметь разные размеры, например. sizeof(char*) != sizeof(int*) разрешено. Однако он требует, чтобы, если указатель преобразуется в void*, а затем преобразован обратно в исходный тип, он должен сравниваться как равный его исходному значению. Следовательно, логически следует, что sizeof(void*) >= sizeof(T*) для всех типов T, правильно?

В большинстве распространенных сегодня платформ (x86, PPC, ARM и 64-битные варианты и т.д.) размер всех указателей равен размеру собственного регистра (4 или 8 байтов), независимо от того, тип. Существуют ли какие-либо эзотерические или встроенные платформы, где указатели на разные типы могут иметь разные размеры? Я специально спрашиваю о указателях данных, хотя мне также было бы интересно узнать, есть ли платформы, где указатели функций имеют необычные размеры.

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

4b9b3361

Ответ 1

Ответ из часто задаваемых вопросов C:

В серии Prime 50 использовался сегмент 07777, смещение 0 для нулевого указателя, по крайней мере для PL/I. В более поздних моделях использовался сегмент 0, смещение 0 для нулевых указателей на C, что требовало новых инструкций, таких как TCNP (Test C Null Pointer), очевидно, как сосок для всего сохранившегося плохо написанного кода на C, который делал неправильные предположения. Более старые, ориентированные на слово Prime машины также были известны тем, что требовали более крупных указателей на байты (char *), чем указатели на слова (int *).

Серия Eclipse MV из Data General имеет три поддерживаемых архитектурой форматов указателей (слова, байт и битовые указатели), два из которых используются компиляторами 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 Машина, отмеченная тегами, даже не имеет обычных числовых указателей; он использует пару (в основном несуществующий дескриптор) как нулевой указатель C.

В зависимости от используемой модели "памяти" 8086-семейные процессоры (ПК совместимые устройства) могут использовать 16-разрядные указатели данных и 32-битную функцию указатели или наоборот.

Некоторые 64-разрядные машины Cray представляют int * в нижних 48 бит слово; char * дополнительно использует некоторые из верхних 16 бит для указания байтовый адрес внутри слова.

Дополнительные ссылки: сообщение от Chris Torek с подробностями о некоторых из этих машин.

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

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

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

Ответ 7

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

Оказывается, это делает gcc-бэкенд болью для развития!:)

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