2015-12-31 3 views
9

Я читаю эту post, который связан с char и byte и попадались следующими словами:Как понять «C++ позволяет sizeof (char *)! = Sizeof (int *)»?

int* все еще может быть реализован в виде одного указателя оборудования, так как C++ позволяет sizeof(char*) != sizeof(int*).

Как понимать 'C++ допускает sizeof(char*) != sizeof(int*)'?

+5

Что * не * вы понимаете об этом? – EJP

+2

@EJP: Разве они не должны быть такими же? –

+2

@Nan: Вы можете объяснить, что заставляет вас думать, что они будут? Это поможет нам понять, какое заблуждение ведет вас к такому выводу. – icktoofay

ответ

2

Короче говоря, стандарт не гарантирует этого, результат определяется реализацией.

От стандарта о sizeof ($ 5.3.3/1 Sizeof [expr.sizeof])

Оператор SizeOf дает число байтов в представлении объекта его операнда.

и указатель типа соединения ($ 3.9.2/1.3 типа соединения [basic.compound])

указатели на VOID или объекты или функции (включая статические члены классов) данного типа , 8.3.1;

и ($ 3.9.2/3 типа соединения [basic.compound])

Значение представления типов указатель определяется реализацией.

, даже если ($ 3.9.2/3 типа соединения [basic.compound])

Указатели на макет-совместимые типы должны иметь одинаковое значение представительства и выравнивания требований (3.11).

но char и int не должны иметь такое же представление значения. Starndard говорит только ($ 3.9.1/2 Основные типы [basic.fundamental])

Там пять стандартных Подписанные целочисленных типов: «подписан символ», «короткие ИНТ», «Int», «длинный ИНТ »И« long long int ». В этом списке каждый тип предоставляет как минимум столько же памяти, сколько и предшествующие ему в списке.

и ($ 3.9.1/3 Основные типы [basic.fundamental]) и т.д.

каждый знаковый целочисленный тип имеет такое же представление объекта в качестве своего соответствующего типа целого числа без знака.

1

Стандарт говорит:

5.3.3 Sizeof
SizeOf (Char), SizeOf (подпись символов) и SizeOf (неподписанные символ) являются: 1. Результат sizeof, примененный к любому другому фундаментальному типу ( 3.9.1), определяется реализацией.

Поскольку указатели являются «составными типами», и стандарт не упоминает о согласованности размера байтов между указателями, авторы компилятора могут делать все, что пожелают.

+2

Он сказал 'sizeof (char *)', а не 'char'. Он спрашивает, почему два указателя могут не иметь одинакового размера. –

+4

@ НикольБолас, который подпадает под «любой другой фундаментальный тип». Указатель на фундаментальный тип является фундаментальным типом, если я не ошибаюсь. – EJP

+4

@EJP: Нет. Указатели не являются фундаментальными. Они сложны. –

3

Существуют (или были) машины, которые могут обращаться только к целым «словам», где слово было достаточно большим, чтобы содержать несколько символов. Например, PDP-6/10 имел размер слова в 36 бит. На такой машине вы можете реализовать 9-битные байты и представлять указатель байтов как комбинацию указателя слова и битового индекса внутри слова. Для наивной реализации потребуется два слова для такого указателя, хотя целочисленный указатель будет всего лишь указателем на слово, занимающим одно слово.

(Реальный PDP-6/10 разрешен для меньших размеров символов - 6-и 7-битные кодировки были обычными, в зависимости от варианта использования, - и поскольку указатель не мог занять целое слово, сделайте указатель на символ, включая смещение бита и адрес слова, в одном слове. Но в подобной архитектуре в наши дни не было бы драконовского ограничения на адресное пространство, так что это больше не будет работать.)

2

itsnotmyrealname и RICi прикосновение аппаратных драйверов для этого, но я думал, что это может помочь пройти через простейший возможный сценарий, ведущий к различным размерам стрелочных ...

Представьте, что процессор может адресовать 32-битные слова памяти и что тип C++ int также должен быть 32 бита в ширину.

Этот гипотетический процессор адресует определенные слова, используя нумерацию: 0 для первого слова (байты 0-3), 1 для второго (байты 4-7) и так далее. Поэтому int*{0} ваше первое слово в памяти (при условии отсутствия странных nullptr махинаций не требуют иного), int*{1} второй и т.д ..

Что должен компилятор сделать, чтобы поддержать 8-битных char типов? Может понадобиться реализовать поддержку char* с помощью int*, чтобы идентифицировать слово в памяти, но для хранения 0, 1, 2 или 3 нужно еще два бита, чтобы указать, к какому из байтов в этом слове указывается. Это эффективно необходимо будет генерировать машинный код, сколько программа C++ может при использовании ...

struct __char_ptr 
{ 
    unsigned* p_; 
    unsigned byte_ : 2; 
    char get() const { return (*p_ & (0xFF << (8*byte_)) >> 8*byte_; } 
    void set(char c) { *p_ &= ~(0xFF << (8*byte_)); *p |= c << 8*byte_; } 
}; 

В такой системе - sizeof(__char_ptr) > sizeof(int*). Гибкость C++ Standard позволяет выполнять совместимые реализации C++ для (и переносимости кода в/из) странных систем с помощью этих или подобных проблем.

2

Это также причина, почему we can not forward declare enums without providing the underlying size в моем ответе. Я предоставляю несколько ссылок, которые объясняют, почему это так.

в этом comp.lang.c++ discussion: GCC and forward declaration of enum:

[...] В то время как на большинстве архитектур это не может быть проблемой, на некоторых архитектур указатель будет иметь различный размер, в случае, если это символ указателя , [...]

и мы можем найти из этой записи C-Faq Seriously, have any actual machines really used nonzero null pointers, or different representations for pointers to different types? он говорит:

Позднее, слово на имя премьер-машины были также пресловутый для требующих больших указателей байт (символ * s), чем слова указатели (int *). [...] Некоторые 64-битные машины Cray представляют int * в младших 48 бит слова; char * дополнительно использует некоторые из верхних 16 бит для указания байтового адреса внутри слова. [...]

и, кроме того:

[...] Серия Затмения MV от общих данных имеют три архитектурно поддерживаемые форматы указатели (слово, байты и биты указатели), два из которые используются компиляторами C: байтовые указатели для char * и void * и указатели слов для всего остального. По историческим причинам в ходе эволюции 32-битной линии MV из 16-разрядной линии Nova указатели на слова и указатели байтов имели биты смещения, косвенности и защиты кольца в разных местах слова. Передача несогласованного формата указателя в функцию привела к ошибкам защиты. В конце концов, компилятор MV C добавил много вариантов совместимости, чтобы попытаться разобраться с кодом, который имел ошибки несоответствия типа указателя. [...] В старых сериях HP 3000 используется другая схема адресации для адресов байтов, чем для адресов слов; как и некоторые из вышеперечисленных машин, поэтому использует разные представления для указателей char * и void *, чем для других указателей. [...]