Есть ли площадки, где указатели на разные типы имеют разные размеры?
стандарт C позволяет указателям на разные типы иметь разные размеры, например sizeof(char*) != sizeof(int*) разрешено. Однако для этого требуется, чтобы указатель был преобразован в void* а затем преобразуется обратно в исходный тип, он должен сравнить как равный своему исходному значению. Поэтому логически следует, что sizeof(void*) >= sizeof(T*) для всех типов T, верно?
на наиболее распространенных платформах, используемых сегодня (x86, PPC, ARM и 64-разрядные варианты и т. д.), размер всех указателей равен размер собственного регистра (4 или 8 байт), независимо от типа указателя. Существуют ли какие-либо эзотерические или встроенные платформы, где указатели на разные типы могут иметь разные размеры? Я специально спрашиваю о сведения указатели, хотя мне также было бы интересно узнать, есть ли платформы, где функции указатели имеют необычные размеры.
Я определенно не запрос о указателе на члены C++и указателе на функции-члены. Те взять на необычные размеры на общих платформах, и даже может варьироваться внутри одной платформы, в зависимости от свойств указателя на класс (не полиморфными, одиночное наследование, множественное наследование, виртуальное наследование, или неполные типа).
7 ответов:
глава 50 серии используется сегмент 07777, смещение 0 для нулевого указателя, по крайней мере для PL/И. более поздние модели использовали сегмент 0, смещение 0 для нулевых указателей в C, что требует новых инструкций, таких как TCNP (тест с нулевым указателем), очевидно, как подачка все дошедшие до нас плохо написанный код на C, который сделал неверные предположения. Более старые, адресованные словам простые машины также были печально известны тем, что требовали больших байтовых указателей (char *'s), чем указатели слов (int *'s).
серия Eclipse MV из Data General имеет три архитектурно поддерживаемых формата указателей (word, byte и bit указатели), два из которых используются компиляторами C: указатели байтов для char * и void * и указатели слов для всего остального. По историческим причинам во время эволюции 32-битной линии MV от 16-битной линии Nova указатели слов и указатели байтов имели смещение, косвенность и биты защиты кольца в разных местах в слове. Передача несогласованного формата указателя функции приводила к ошибкам защиты. В конце концов, компилятор MV C добавил много параметров совместимости, чтобы попытаться справиться с кодом, который имел ошибки несоответствия типов указателей.
некоторые мэйнфреймы Honeywell-Bull используют битовый шаблон 06000 для (внутренних) нулевых указателей.
CDC Cyber 180 Series имеет 48-битные указатели, состоящие из кольца, сегмента и смещения. Большинство пользователей (в кольце 11) имеют нулевые указатели 0xB00000000000. Это было общие на старых CDC-дополняют машины, чтобы использовать все-одно-битное слово в качестве специального флага для всех видов данных, включая недопустимые адреса.
старая серия HP 3000 использует другую схему адресации для байтовых адресов, чем для адресов word; как и некоторые из машин выше, она поэтому использует различные представления для указателей char * и void*, чем для других указателей.
машина Symbolics Lisp, помеченная архитектура, даже не имеет обычные числовые указатели; он использует пару (в основном несуществующий дескриптор) в качестве нулевого указателя C.
в зависимости от используемой "модели памяти", 8086-процессоры семейства (ПК compatibles) может использовать 16-разрядные указатели данных и 32-разрядную функцию указатели, или наоборот.
некоторые 64-разрядные машины Cray представляют int * в нижних 48 битах a слово; 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));выход:
пинта: 2, fpInt 4
следовательно, логически следует, что
sizeof(void*) >= sizeof(T*)для всех типов T, правильно?это не обязательно следует, так как sizeof-это представление хранилища, и не все битовые шаблоны должны быть допустимыми значениями. Я думаю, что вы могли бы написать соответствующую реализацию, где
sizeof(int*) == 8,sizeof(void*) == 4, но не более 2^32 возможных значений для int*. Не знаю, зачем тебе это нужно.
еще в золотые годы DOS, 8088s и сегментированной памяти было принято указывать "модель памяти", в которой, например, весь код будет вписываться в 64k (один сегмент), но данные могут охватывать несколько сегментов; это означало, что указатель функции будет 2 байта, указатель данных, 4 байта. Не уверен, что кто-то все еще программирует для машин такого рода, возможно, некоторые все еще выживают во встроенных применениях.
можно легко представить себе машину архитектуры Гарварда, имеющую разные размеры для указателей функций и всех других указателей. Не знаю ни одного примера...
Ближний и Дальний указатели по-прежнему используются на некоторых встроенных микроконтроллерах с выгружаемой вспышкой или ОЗУ, чтобы вы могли указывать на данные на той же странице (Ближний указатель) или на другой странице (дальний указатель, который больше, потому что он включает информацию о странице).
например, микроконтроллер Hcs12 Freescale использует 16-битную архитектуру фон Неймана, что означает, что ни один адрес не может быть больше 16 бит. Из-за ограничения это поставило бы на объем доступного кодового пространства, там это 8-битный регистр страниц.
таким образом, чтобы указать на данные в той же кодовой странице, вы просто указываете 16-разрядный адрес; это Ближний указатель.
чтобы указать на данные в другой кодовой странице, вы должны включить как 8-битный номер страницы, так и 16-битный адрес внутри этой страницы, что приведет к 24-битному указателю far.
возможно, что размер указателей на данные отличается от указателей на функции, например. Обычно это происходит в микропроцессоре для встроенной системы. Машины архитектуры Гарварда, такие как dmckee, упомянутые, делают это легко.
оказывается, что это делает GCC backends боль, чтобы развиваться! :)
Edit: я не могу вдаваться в детали конкретной машины, о которой я говорю, но позвольте мне добавить, почему машины Гарварда делают это легко. Этот Архитектура Harvard имеет разные хранилища и пути к инструкциям и данным, поэтому, если шина для инструкций "больше", чем для данных, у вас обязательно будет указатель функции, размер которого больше, чем указатель на данные!
Comments