Каков размер long в 64-битной Windows?

137

Не так давно кто-то сказал мне, что longна 64-битных машинах нет 64 бит, и я всегда должен их использовать int. Это не имело смысла для меня. Я видел, как документы (например, на официальном сайте Apple) говорят, что longони действительно 64-битные при компиляции для 64-битного процессора. Я посмотрел, что это было на 64-битной Windows и нашел

  • Windows: longи intостаются 32-разрядными по длине, а для 64-разрядных целых чисел определены специальные новые типы данных.

http://www.intel.com/cd/ids/developer/asmo-na/eng/197664.htm?page=2 )

Что я должен использовать? Должен ли я определить что - то вроде uw, sw((ООН) подписали ширину) , как longесли не на Windows, а в противном случае выполнить проверку на bitsize целевого процессора?

Чаба
источник
В Windows с MSVC ++ int и long являются 32-разрядными: msdn.microsoft.com/en-us/library/3b2e7499.aspx . Однако, чтобы, например, векторы могли хранить более 4G элементов, size_t является 64-битным. Поэтому нужно использовать int64_t вместо int для итерации, например, векторов, которые могут содержать более 4G элементов.
Серж Рогач
@SergeRogatch они должны использовать size_tили тип итератора для итерации, не intилиint64_t
phuclv
2
@ LưuVĩnhPhúc, с size_tним становится сложно около отрицательных чисел, потому что size_tбез знака. Так for(size_t i=0; i<v.size()-2; i++)не выполняется для вектора размера 0 и 1. Другой пример: for(size_t i=v.size()-1; i>=0; i--).
Серж Рогач
2
Если вы делаете математику на указатели (т.е. с size_tзначениями , то результат должен быть сохранен в переменной ptrdiff_tтипа - который разработан , чтобы быть достаточно большим , чтобы провести такой результат и является подписанный тип именно по этой причине!)
SlySven

Ответы:

261

В мире Unix было несколько возможных вариантов размеров целых чисел и указателей для 64-битных платформ. Двумя наиболее широко используемыми были ILP64 (на самом деле, примеров было очень мало; Cray был одним из них) и LP64 (почти для всего остального). Сокращения происходят от «int, long, указатели 64-битные» и «long, указатели 64-битные».

Type           ILP64   LP64   LLP64
char              8      8       8
short            16     16      16
int              64     32      32
long             64     64      32
long long        64     64      64
pointer          64     64      64

Система ILP64 была заброшена в пользу LP64 (то есть почти все последующие участники использовали LP64, основываясь на рекомендациях группы Aspen; только системы с длительным наследием 64-битной работы используют другую схему). Все современные 64-битные системы Unix используют LP64. MacOS X и Linux являются современными 64-битными системами.

Microsoft использует другую схему перехода на 64-битную версию: LLP64 («long long, указатели 64-битные»). Это означает, что 32-разрядное программное обеспечение можно перекомпилировать без изменений. Он отличается от того, что делают все остальные, а также требует пересмотра кода для использования 64-битных возможностей. Там всегда был пересмотр необходим; это был просто набор ревизий, отличающийся от тех, которые нужны на платформах Unix.

Если вы разрабатываете свое программное обеспечение на основе имен целочисленных типов, не зависящих от платформы, возможно, используя <inttypes.h>заголовок C99 , который, когда типы доступны на платформе, обеспечивает подпись (в списке) и без знака (не в списке; префикс с «u»):

  • int8_t - 8-битные целые числа
  • int16_t - 16-битные целые числа
  • int32_t - 32-разрядные целые числа
  • int64_t - 64-разрядные целые числа
  • uintptr_t - целые числа без знака, достаточно большие, чтобы содержать указатели
  • intmax_t- самый большой размер целого на платформе (может быть больше, чем int64_t)

Затем вы можете кодировать свое приложение, используя эти типы, где это важно, и быть очень осторожными с типами системы (которые могут отличаться). Существует intptr_tтип - целочисленный тип со знаком для хранения указателей; Вы должны планировать не использовать его или использовать только как результат вычитания двух uintptr_tзначений ( ptrdiff_t).

Но, как указывает вопрос (с недоверием), существуют разные системы для размеров целочисленных типов данных на 64-битных машинах. Привыкнуть к этому; мир не изменится.

Джонатан Леффлер
источник
12
Для тех, кто использовался достаточно долго, 64-битный переход имеет некоторые параллели с 16-битным и 32-битным переходом середины 80-х. Были компьютеры, которые были IL32 и другие, которые были L32 (адаптируя новую нотацию к старой проблеме). Иногда int был 16-разрядным, иногда 32-разрядным.
Джонатан Леффлер
4
Не забывайте, что это относится только к языкам C-ish. Другие имеют более точные спецификации, в которых: а) автору компилятора не разрешается выбирать размер типов данных произвольно или б) физическое представление типов данных не «просачивается» или в) целые числа всегда бесконечно велики.
Йорг Миттаг
2
Верно - но для тех языков, которые определяют поведение, в первую очередь нет проблем. Например, Java имеет «long», но размер является фиксированным (64-битным?) На всех платформах. Таким образом, нет проблем с портированием на 64-битную машину; размер не меняется.
Джонатан Леффлер
17
@TomFobear: ILP64 представляет одну серьезную проблему - что вы называете 32-битным типом? Или, если вы называете 32-битный тип short, что вы называете 16-битным типом? И если вы вызываете 16-битный тип charдля UTF-16 и т. Д., Что вы называете 8-битным типом? Таким образом, использование LP64 оставляет вас с 8-битным char, 16-битным short, 32-битным int, 64-битным long, с возможностью расширения вверх до 128-бит, long longкогда (если?) Это становится актуальным. После этого у вас больше степеней 256, чем у вас имен в C (ну, я полагаю, у вас может быть 256-битная intmax_t, и только тогда вы исчерпаете). В этом есть заслуга LP64.
Джонатан Леффлер
2
Возможно, это очевидно для вас, ребята, но я думаю, что стоит отметить, что C # использует целочисленные размеры, отличные от всего остального. Недавно я столкнулся с интерфейсом DLL, так как C # использует 64-битные longs ( msdn.microsoft.com/en-us/library/ms173105.aspx ).
Compholio
57

Не ясно, если речь идет о компиляторе Microsoft C ++ или Windows API. Однако тега [c ++] нет, поэтому я предполагаю, что он касается API Windows. Некоторые ответы пострадали от гниения ссылок, поэтому я предоставляю еще одну ссылку, которая может гнить.


Для получения информации о типах API Windows, таких как INTи LONGт. Д., Есть страница в MSDN:

Типы данных Windows

Информация также доступна в различных заголовочных файлах Windows, таких как WinDef.h. Я перечислил несколько соответствующих типов здесь:

Тип | S / U | х86 | x64
---------------------------- + ----- + -------- + ------ -
БАЙТ, БУЛЬЯНСКИЙ | U | 8 бит | 8 бит
---------------------------- + ----- + -------- + ------ -
КОРОТКИЙ | S | 16 бит | 16 бит
USHORT, WORD | U | 16 бит | 16 бит
---------------------------- + ----- + -------- + ------ -
INT, LONG | S | 32 бит | 32 бит
UINT, ULONG, DWORD | U | 32 бит | 32 бит
---------------------------- + ----- + -------- + ------ -
INT_PTR, LONG_PTR, LPARAM | S | 32 бит | 64 бит
UINT_PTR, ULONG_PTR, WPARAM | U | 32 бит | 64 бит
---------------------------- + ----- + -------- + ------ -
ДЛИННЫЕ | S | 64 бит | 64 бит
УЛОНГЛОНГ, QWORD | U | 64 бит | 64 бит

Столбец «S / U» обозначает подписанный / неподписанный.

Мартин Ливерсаж
источник
4

Эта статья о MSDN ссылается на ряд псевдонимов типов (доступных в Windows), которые немного более явны в отношении их ширины:

http://msdn.microsoft.com/en-us/library/aa505945.aspx

Например, хотя вы можете использовать ULONGLONG для ссылки на 64-разрядное целое число без знака, вы также можете использовать UINT64. (То же самое касается ULONG и UINT32.) Возможно, это будет немного яснее?

Рувим
источник
1
Есть ли гарантия, что uint32_t и DWORD будут взаимозаменяемыми? Нетрудно представить, что они могут не быть (например, если первый 32-битный, intа второй 32-битный long, gcc будет предполагать, что указатель на один тип не сможет псевдоним другого, несмотря на их соответствующие представления).
суперкат
4

Microsoft также определила UINT_PTR и INT_PTR для целых чисел того же размера, что и указатель.

Вот список специфических типов Microsoft - это часть справочника по драйверам, но я считаю, что он действителен и для общего программирования.

Марк Рэнсом
источник
2

Самый простой способ узнать это для вашего компилятора / платформы:

#include <iostream>

int main() {
  std::cout << sizeof(long)*8 << std::endl;
}

Умножение на 8 состоит в получении битов из байтов.

Когда вам нужен определенный размер, часто проще всего использовать один из предопределенных типов библиотеки. Если это нежелательно, вы можете делать то, что часто происходит с программным обеспечением autoconf, и система конфигурации определяет правильный тип для нужного размера.

Поль де Вриз
источник
4
Не то чтобы это важно, но 8-битные байты на самом деле не являются частью спецификации C (пп. 3.6 и 5.2.4.2.1 стандарта C). Хотя вам будет сложно найти машину, в которой не будет 8 бит, вы можете проверить LONG_BIT, чтобы увидеть, насколько велик ваш длинный тип данных.
Андрес
Конечно, вы правы, на самом деле это зависит от архитектуры («адресуемая единица хранения данных, достаточно большая, чтобы вместить любой элемент базового набора символов среды выполнения»), но наиболее часто используемая архитектура, равная 8 битам.
Поль де Вриз
Но ОП не спрашивал о его компиляторе / платформе; он спросил конкретно о 64-битной Windows - возможно потому, что у него нет удобного доступа к 64-битной системе Windows для тестирования.
Quuxplusone
0

Размер в битах longна платформах Windows составляет 32 бита (4 байта).

Вы можете проверить это, используя sizeof(long).

BeeOnRope
источник
-2

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

PolyThinker
источник