c++ - Кто определяет размер любого типа данных или структуры(в зависимости от 32-битного или 64-битного)?




linux compiler-construction (5)

Дизайнер процессора определяет, какие регистры и инструкции доступны, каковы правила выравнивания для эффективного доступа, насколько большие адреса памяти и так далее.

Стандарт C устанавливает минимальные требования для встроенных типов. «char» должен быть не менее 8 бит, «короткий» и «int» должен быть не менее 16 бит, «long» должен быть не менее 32 бит, а «long long» должен быть не менее 64 бит. В нем также говорится, что «char» должен быть эквивалентен наименьшей единице памяти, которую может решить программа, и что порядок размеров стандартных типов должен поддерживаться.

Другие стандарты также могут оказать влияние. Например, версия 2 «единой спецификации Unix» говорит, что int должен быть не менее 32 бит.

Наконец, существующий код оказывает влияние. Портирование уже достаточно тяжело, никто не хочет сделать это сложнее, чем нужно.

При переносе ОС и компилятора на новый процессор кто-то должен определить, что известно как «C ABI». Это определяет, как двоичный код взаимодействует друг с другом.

  • Требования к размеру и выравниванию встроенных типов.
  • Правила упаковки для конструкций (и, следовательно, их размер).
  • Как параметры передаются и возвращаются
  • Как управлять стеком

В общем случае один раз и ABI определен для комбинации семейства процессоров и ОС, он не сильно меняется (иногда размер более неясных типов, таких как «длинные двойные» изменения). Изменение его приносит кучу поломки для относительно небольшого выигрыша.

Аналогично, перенос ОС на платформу со схожими характеристиками с существующей будет обычно выбирать те же размеры, что и на предыдущих платформах, на которые была перенесена ОС.

На практике поставщики ОС / компиляторов обычно располагаются в одной из нескольких комбинаций размеров для основных целых типов.

  • «LP32»: char - 8 бит. short и int - 16 бит, long и указатель - 32 бит. Обычно используется на 8-битных и 16-разрядных платформах.
  • «ILP32»: char - 8 бит, короткий - 16 бит. int, long и указатель - все 32 бита. Если долгое время существует, это 64 бит. Обычно используется на 32-битных платформах.
  • «LLP64»: char - 8 бит. короткий - 16 бит. int и long - 32 бита. long long и указатель - 64 бит. Используется в 64-битных окнах.
  • «LP64»: char - 8 бит. короткий - 16 бит. int - 32 бита. длинный, длинный и указательный - 64 бит. Используется в большинстве 64-разрядных Unix-подобных систем.
  • «ILP64»: char - 8 бит, короткий - 16 бит, int, long и указатель и long long - все 64 бит. По-видимому, он используется на некоторых ранних 64-битных операционных системах, но редко встречается в наши дни.

64-разрядные процессоры обычно могут запускать как 32-битные, так и 64-битные двоичные файлы. Как правило, это связано с наличием уровня совместимости в вашей ОС. Таким образом, ваш 32-битный двоичный код использует те же типы данных, которые он будет использовать при работе в 32-разрядной системе, тогда уровень совместимости переводит системные вызовы, чтобы 64-разрядная ОС могла их обрабатывать.

Кто определяет размер любого типа данных или структуры (в зависимости от 32-битного или 64-битного)? Компилятор или процессор? Например, sizeof(int) составляет 4 байта для 32-битной системы, тогда как для 64-разрядной системы это 8 байтов.

Я также читал, что sizeof(int) составляет 4 байта при компиляции с использованием как 32-битного, так и 64-битного компилятора .

Предположим, что мой процессор может работать как с 32-разрядными, так и с 64-разрядными приложениями, кто будет играть основную роль в определении размера данных компилятора или процессора ?


Когда вы говорите о компиляторе, вы получаете чистое изображение о build|host|target , то есть машине, на которой вы строите (сборку), машине, которую вы строите для (хост), и машине, которую GCC будет производить код для (target), потому что для «кросс-компиляции» очень отличается от «native compiling».

Что касается вопроса «кто определяет размер и тип данных», это зависит от целевой системы, которую вы сказали компилятору для создания двоичного кода. Если целью является 64 бита, компилятор переведет sizeof (long) в 8, и если цель будет 32-битной машиной, компилятор переведет sizeof (long) в 4. Все они были предопределены файлом заголовка, который вы использовали для сборки вашей программы. Если вы читаете свой `$ MAKETOP / usr / include / stdint.h ', для определения размера вашего типа данных существуют typedefs.

Чтобы избежать ошибки, созданной разницей в размерах, стиль кодирования Google-Integer_Types рекомендует использовать такие типы, как int16_t, uint32_t, int64_t и т. Д. Они были определены в <stdint.h> .

Выше представлены только те «Обычные старые данные», как int. Если вы говорите о структуре, есть еще одна история, потому что размер структуры зависит от выравнивания упаковки, выравнивания границ для каждого поля в структуре, что окажет влияние на размер структуры.


Это компилятор, а точнее его компонент кода.

Конечно, компилятор обладает поддержкой архитектуры и делает выбор, соответствующий этому.

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


Это не процессор, ни компилятор, ни операционная система. Это все три одновременно.

Компилятор не может просто разобраться. Он должен придерживаться права ABI [1], что обеспечивает операционная система. Если структуры и системные вызовы, предоставляемые операционной системой, имеют типы с определенными размерами и требованиями к выравниванию, компилятор не может свободно создавать свою собственную реальность, если разработчики компилятора не хотят переопределять функции-оболочки для всего, что предоставляет операционная система. Тогда ABI операционной системы не может быть просто полностью составлен, он должен делать то, что можно разумно сделать на CPU. И очень часто ABI одной операционной системы будет очень похож на другие ABI для других операционных систем на одном процессоре, потому что проще просто повторить работу, которую они выполняли (в компиляторах между прочим).

В случае компьютеров, поддерживающих как 32-битный, так и 64-битный код, все еще необходимо выполнить работу операционной системы для поддержки запущенных программ в обоих режимах (поскольку система должна обеспечивать два разных ABI). Некоторые операционные системы этого не делают, и на тех, у кого нет выбора.

[1] ABI означает Application Binary Interface. Это набор правил взаимодействия программы с операционной системой. Он определяет, как программа хранится на диске для запуска операционной системой, как выполнять системные вызовы, как связываться с библиотеками и т. Д. Но для того, чтобы иметь возможность ссылаться на библиотеки, например, ваша программа и библиотека должны соглашаться о том, как делать вызовы функций между вашей программой, библиотекой (и наоборот) и иметь возможность совершать вызовы функций, как программа, так и библиотека должны иметь одинаковую идею о расположении стека, использовании регистров, условных вызовах функций и т. д. А для вызовов функций вам нужно согласовать, что означают параметры, и включает в себя размеры, выравнивание и подпись типов.


Это, в конечном счете, компилятор. Разработчики компилятора могут решить эмулировать любой целочисленный размер, который им подходит, независимо от того, что процессор обрабатывает наиболее эффективно. Тем не менее, стандарт C (и C ++) написан таким образом, что разработчик компилятора может выбрать самый быстрый и эффективный способ. Для многих компиляторов разработчики решили сохранить int как 32 бит, хотя процессор изначально обрабатывает 64-битные ints очень эффективно.

Я думаю, что это было сделано частично для увеличения переносимости программ, написанных, когда 32-битные машины были наиболее распространенными и ожидали, что int будет 32 бит и больше не будет. (Также может быть, как указывает пользователь user3386109 , что 32-битные данные были предпочтительнее, поскольку они занимают меньше места и, следовательно, могут быть доступны быстрее).

Поэтому, если вы хотите убедиться, что вы получаете 64-битные int, вы используете int64_t вместо int чтобы объявить свою переменную. Если вы знаете, что ваше значение будет соответствовать 32 битам или вам не нужен размер, вы можете использовать int чтобы компилятор мог выбрать наиболее эффективное представление.

Что касается других типов данных, таких как struct , они состоят из базовых типов, таких как int .





operating-system