Не так давно кто-то сказал мне, что long не являются 64-битными на 64-битных машинах, и я всегда должен использовать int. Для меня это не имело смысла. Я видел документы (например, на официальном сайте Apple), в которых говорится, что long действительно 64-битные при компиляции для 64-битного процессора. Я посмотрел, что это было в 64-битной Windows, и обнаружил
- Windows:
longandintremain 32-bit in length, and special new data types are defined for 64-bit integers.
(от http://www.intel.com/cd/ids/developer/asmo-na/eng/197664.htm?page=2)
Что мне использовать? Должен ли я определить что-то вроде uw, sw ((без) подписанной ширины) как long, если не в Windows, а в противном случае проверить размер целевого процессора в битах?
@SergeRogatch они должны использовать size_t или тип итератора для итерации, а не int или int64_t
@ 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--).
Если вы выполняете математические вычисления с указателями (т.е. со значениями size_t, тогда результат должен храниться в переменной типа ptrdiff_t, которая должна быть достаточно большой для хранения такого результата и является типом подписанный именно по этой причине!)
@rustyx - это компиляторы, а не операционные системы. Cygwin скомпилирован с использованием mingw (порт GCC для Windows) в качестве компилятора. Как и GCC в Linux, он может определять long как 64-битный, однако MSVC++ (компилятор Microsoft) определяет его как 32-битный.
@OrionEdwards На самом деле речь идет о целевой платформе ABI. Cygwin имеет собственный POSIX-подобный ABI и выбирает более удобную для POSIX модель LLP64, тогда как Mingw придерживается Win32 ABI со своей моделью LP64. По этой причине в GCC в комплекте с Mingw long составляет 32 бита, а в GCC в Cygwin - 64 бита.
@rustyx Я чувствую, что мы разговариваем друг с другом. Я хочу сказать, что long существует только в мире компилятора и соглашений, которых он ожидает. Когда дело доходит до запуска кода, это просто «По этому адресу 8 байтов», а термины int, long и т. д. Не существуют.





Если вам нужно использовать целые числа определенной длины, вам, вероятно, следует использовать некоторые независимые от платформы заголовки, чтобы помочь вам. Boost - хорошее место, чтобы посмотреть.
Эта статья в MSDN ссылается на ряд псевдонимов типов (доступных в Windows), которые несколько более явны в отношении их ширины:
http://msdn.microsoft.com/en-us/library/aa505945.aspx
Например, хотя вы можете использовать ULONGLONG для ссылки на 64-битное целочисленное значение без знака, вы также можете использовать UINT64. (То же самое и с ULONG и UINT32.) Может быть, они будут немного понятнее?
Есть ли гарантия, что uint32_t и DWORD будут взаимозаменяемыми? Нетрудно представить, что они могут не быть [например, если первый - 32-битный int, а второй - 32-битный long, gcc будет предполагать, что указатель на один тип не сможет создать псевдоним другого, несмотря на их совпадающие представления].
Самый простой способ узнать это для вашего компилятора / платформы:
#include <iostream>
int main() {
std::cout << sizeof(long)*8 << std::endl;
}
Умножение на 8 позволяет получить биты из байтов.
Когда вам нужен определенный размер, часто проще всего использовать один из предопределенных типов библиотеки. Если это нежелательно, вы можете сделать то, что часто случается с программой autoconf, и попросить систему конфигурации определить правильный тип для необходимого размера.
Не то чтобы это важно, но 8-битные байты на самом деле не являются частью спецификации C (пункты 3.6 и 5.2.4.2.1 стандарта C). Хотя вам будет сложно найти машину, на которой не было бы 8 бит, вы можете проверить LONG_BIT, чтобы узнать, насколько велик ваш длинный тип данных.
Конечно, вы правы, это фактически зависит от архитектуры («адресуемая единица хранения данных, достаточно большая, чтобы вместить любой член базового набора символов среды выполнения»), но наиболее часто используемые архитектуры равны 8 битам.
Но OP не спрашивал о компиляторе / платформе его; он спросил конкретно о 64-битной Windows - вероятно, потому что у него не есть удобный доступ к 64-битной системе Windows для тестирования.
Microsoft также определила UINT_PTR и INT_PTR для целых чисел того же размера, что и указатель.
Вот список конкретных типов Microsoft - это часть их справочника по драйверам, но я считаю, что это справедливо и для общего программирования.
В мире 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.
Если вы разрабатываете свое программное обеспечение вокруг нейтральных к платформе имен целочисленных типов, возможно, используя заголовок C99 <inttypes.h>, который, когда типы доступны на платформе, предоставляет подписанные (перечисленные) и неподписанные (не перечисленные; префикс с '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-битных машинах. Привыкайте к этому; мир не изменится.
Для тех, кто работает уже достаточно давно, 64-битный переход имеет некоторые параллели с переходом от 16-битного к 32-битному переходу середины 80-х годов. Были компьютеры с IL32 и другие с L32 (адаптация новой нотации к старой проблеме). Иногда int было 16-битным, иногда 32-битным.
Не забывайте, что это относится только к Си-иш. У других есть более разумные спецификации, где а) разработчику компилятора не разрешается выбирать размер типов данных волей-неволей или б) физическое представление типов данных не "утекает" или в) целые числа всегда бесконечно велики.
Верно, но для тех языков, которые определяют поведение, в первую очередь нет проблемы. Например, в Java есть «длинный», но размер фиксированный (64-битный?) На всех платформах. Так что проблем с переносом на 64-битную машину нет; размер не меняется.
Утверждать, что Alpha была / есть ILP64, неверно. OpenVMS, Tru64 и Linux, работающие на Alpha, - это «просто» LP64.
@Daniel: спасибо за исправление - я обновил ответ более или менее подходящим образом.
вы думаете, что ILP64 будет более популярным, не было бы проще обрабатывать 64-битный тип данных на 64-битном процессоре?
@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 есть заслуга.
Возможно, это очевидно для вас, ребята, но я думаю, что стоит отметить, что C# использует целые числа, отличные от всего остального. Недавно я столкнулся с проблемой взаимодействия с DLL, поскольку C# использует 64-битные длинные (msdn.microsoft.com/en-us/library/ms173105.aspx).
@Compholio: Для меня это было совершенно не очевидно, но я не программировал на C#. В Java тоже есть свой набор фиксированных размеров для целых чисел.
@ Джонатан Леффлер, когда вы говорите, что код должен быть изменен для использования 64-битных возможностей, вы имеете в виду ограничение в 2 ^ 32 элемента в массиве? Я предполагаю, что вы все еще можете использовать более 4 ГБ кучи для нескольких распределений, например. Знаете ли вы, есть ли индексы в контейнерах типа массива в реализациях MS контейнеров STL 32 бит?
В среде Windows, чтобы использовать 64-битные целые числа в программе, изначально написанной для 32-битной среды, вы должны изменить тип некоторых переменных (в общем). Напротив, в среде LP64 любые переменные типа long автоматически становятся 64-битными при переносе кода. Размеры массивов и т. д. Могут быть проблемой, но если вы выделяете несколько гигабайт памяти, вы обычно знаете об этом и уже предприняли шаги для работы с объектами большого размера.
Документ из X / Open на 64-битные модели программирования: почему именно LP64?. См. Также Нейтралитет размера данных и поддержка 64-битной версии.
@JonathanLeffler: На протяжении десятилетий в области микрокомпьютеров char, short и long были типами фиксированного размера с 8, 16 и 32 битами соответственно. Размер int будет 16 на одних платформах и 32 на других, но код, требующий 16-битного типа, может использовать short, а код, требующий 32-битного типа, может использовать long. Колеса отваливаются, только если int становится 64-битным.
Спасибо за объяснение аббревиатур, стоящих за ILP64, LLP64, LP64!
На мой взгляд, одна из ошибок C заключалась в том, что не были указаны размеры различных интегральных типов данных. Для программиста объявление переменной без знания максимального значения размера, которое она может содержать, в лучшем случае является сомнительной практикой кодирования. В конце концов, все программисты вынуждены делать некоторые предположения о размерах интегральных типов, и тот факт, что спецификация C не соответствует этой реальности, является ошибкой.
Если бы вы изобретали C заново сегодня, даже если оглянуться назад на 20:20 и иметь 45-летний опыт работы с C, неясно, что вы сделаете это изменение. Существует много различных типов ЦП, и разумные конструктивные решения для 8-битного или 16-битного ЦП не обязательно будут разумными для 64-битного ЦП. Я считаю, что есть еще несколько систем, в которых размер слова не является степенью двойки; их было намного больше, когда был изобретен C. Стандарт - это договор между разработчиками компилятора и программистами, которые его используют. Если вы будете внимательно следовать правилам, вы сможете написать переносимый код.
@deltamind: Легко сказать в ретроспективе, но изначально C должен был работать на машинах с 18-битными и 15-битными целыми числами и 7-битными символами, которые, к счастью, уже не в моде.
Возможно, стоит упомянуть, что ABI ILP32 в 64-битном режиме - это вещь (например, AArch64 ILP32 и x86-64 Linux x32), поэтому проверка sizeof(size_t) или sizeof(void*), чтобы определить, поддерживаются ли 64-битные целые числа изначально / эффективно, может по-прежнему иметь ложноотрицательные результаты. Я не знаю, называет ли это это моделью LL64 (где только long long 64-битный).
Неясно, идет ли речь о компиляторе Microsoft C++ или Windows API. Однако тега [C++] нет, поэтому я предполагаю, что это касается Windows API. Некоторые ответы пострадали от гниения ссылок, поэтому я предлагаю еще одну ссылку, которая может гнить.
Для получения информации о типах Windows API, таких как INT, LONG и т. д., Есть страница в MSDN:
Информация также доступна в различных заголовочных файлах Windows, таких как WinDef.h. Я перечислил здесь несколько подходящих типов:
Type | S/U | x86 | x64 ----------------------------+-----+--------+------- BYTE, BOOLEAN | U | 8 bit | 8 bit ----------------------------+-----+--------+------- SHORT | S | 16 bit | 16 bit USHORT, WORD | U | 16 bit | 16 bit ----------------------------+-----+--------+------- INT, LONG | S | 32 bit | 32 bit UINT, ULONG, DWORD | U | 32 bit | 32 bit ----------------------------+-----+--------+------- INT_PTR, LONG_PTR, LPARAM | S | 32 bit | 64 bit UINT_PTR, ULONG_PTR, WPARAM | U | 32 bit | 64 bit ----------------------------+-----+--------+------- LONGLONG | S | 64 bit | 64 bit ULONGLONG, QWORD | U | 64 bit | 64 bit
Столбец «S / U» обозначает знаковый / беззнаковый.
В Windows с MSVC++ int и long являются 32-битными: msdn.microsoft.com/en-us/library/3b2e7499.aspx. Однако, чтобы разрешить, например, векторы для хранения более 4G элементов, size_t - 64 бит. Поэтому для итерации нужно использовать int64_t вместо int, например. векторы, которые могут содержать более 4G элементов.