Ключевое слово C register
не влияет на ширину выбранного вами типа C.int
- это 32-разрядный тип во всех 32- и 64-разрядных интерфейсах x86 ABI, включая x86-64 System V и Windows x64.(long
также 32-битный в Windows x64, но 64-битный в Linux / Mac / все остальное x86-64 1 .)
A register int
по-прежнему int
, с учетом всех ограничений INT_MAX
, INT_MIN
, а переполнение со знаком является неопределенным поведением. Это не превращает ваш источник C в переносимый язык ассемблера.
Использование register
просто говорит компилятору, что даже в режиме отладки можно свободно хранить переменную (младшая половинаof) регистр.
Если регистр имеет 64 бита, почему условное обозначение int должно быть 32 бита
int
равно 32-бит, потому что никто не хочет, чтобы массив int
становился 64-битным на 64-битной машине, имея удвоенную площадь кеша.
Я не знаю ни одной реализации C, где int
= int64_t
, даже вне x86-64.Даже DEC Alpha (который был агрессивно 64-битным и разработан с нуля для 64-битных), я думаю, все еще использовал 32-битный int.
Создание int
32-битных при увеличении с 16 до 32-битных машин имеет смысл, потому что 16-битные "слишком малы" иногда.(Но помните, что ISO C гарантирует, что int
составляет не менее 16 бит. Если вам нужно больше, в действительно переносимой программе лучше использовать long
или int_least32_t
.)
Но 32 бита "достаточно велико" для большинства программ, и 64-битные машины всегда имеют быстрые 32-битные целые числа, поэтому int
остается 32-битным при переходе с 32-битных 64-битных машин.
На некоторых машинах 16-битные целые числа не очень хорошо поддерживаются.например, реализация преобразования в 16 битов с uint16_t
в MIPS потребует дополнительных непосредственных инструкций AND.Поэтому сделать int
16-битным типом было бы плохим выбором.
На x86 вы можете просто использовать 16-битный размер операнда и использовать movzx
вместо mov
при копировании, ноэто нормально для int
быть 32-битным на 32-битных машинах, поэтому все 32-битные ABI x86 выбрали это.
Когда ISA были расширены с 32 до 64-битных, былопричина нулевой производительности сделать int
шире , в отличие от случая 16-> 32.(Также в этом случае short
оставался 16-разрядным, поэтому существовало точное имя для 16- и 32-разрядных целых чисел, даже до появления C99 stdint.h
).
В x86-64, операнде по умолчаниюразмер по-прежнему 32-битный;mov rax, rcx
занимает дополнительный байт префикса (REX.W) по сравнению с mov eax, ecx
, поэтому 32-битный немного более эффективен.Кроме того, 64-разрядное умножение было немного медленнее на некоторых процессорах, а 64-разрядное деление значительно медленнее, чем 32-разрядное, даже на современных процессорах Intel. Преимущества использования 32-битных регистров / инструкций в x86-64
Кроме того, компиляторам нужен примитивный тип для int32_t
, если они хотят предоставить дополнительный int32_t
ввсе.(Типы дополнения с фиксированной шириной 2 являются необязательными, в отличие от int_least32_t
и т. Д., Которые, как гарантируют, не будут дополнением 2 или свободны от дополнения.)
Компиляторы с 16-разрядными short
и 64-bit int
может иметь имя типа, специфичное для реализации, например __int32
, которое они используют в качестве typedef для int32_t
/ uint32_t
, поэтому этот аргумент не является полным showtopper.Но это было бы странно.
При увеличении с 16 до 32 имеет смысл изменить int
на более широкий, чем минимум ISO C, потому что у вас все еще есть short
в качестве имени для 16-битного,(Этот аргумент не очень хорош, потому что у вас есть long
в качестве имени для 32-разрядных целых чисел в 32-разрядных системах.)
Но при переходе на 64-разрядную версию вы хотите *Тип 1090 * some должен быть 32-битным целочисленным типом.(И long
не может быть уже int
).char
/ short
/ int
/ long
(или long long
) охватывает все 4 возможных размера операндов. int32_t
не гарантированно будет доступно во всех системах, поэтому ожидаем, что всеиспользуйте это, если они хотят, чтобы 32-разрядные целые числа со знаком не были приемлемыми для переносимого кода.
Сноска 1 :
Вы можете в любом случае утверждать, лучше ли для long
быть 32- или 64-битным типом.Решение Microsoft оставить его 32-битным означало, что структурные макеты, использующие long
, могут не меняться между 32-битным и 64-битным кодом (но они могли бы, если бы они включали указатели).
ISO C требует, чтобы long
былопо крайней мере, 32-битный тип (на самом деле они определяют его в терминах минимального и максимального значений, которые могут быть представлены, но в других местах они требуют, чтобы целочисленные типы были двоичными целыми числами с необязательным заполнением).
В любом случае, некоторыекод использует long
, потому что ему нужен 32-битный тип, но ему не нужен 64;во многих случаях больше битов не лучше, они просто не нужны.
В пределах одного ABI, такого как x86-64 System V, всегда удобно иметь длину long равной указателю,но так как переносимый код всегда должен использовать unsigned long long
или uint64_t
или uint_least64_t
или uintptr_t
в зависимости от варианта использования, для System v x86-64 было бы ошибкой выбрать 64-битную длину.
OTOH, более широкие типы для локальных пользователей могут иногда сохранять инструкции, избегая расширения знака при индексировании указателя, но тот факт, что переполнение со знаком является неопределенным поведением, часто позволяет компиляторам расширять int
в asm, когда это удобно.