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

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

  • Windows: long and int remain 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, а в противном случае проверить размер целевого процессора в битах?

В Windows с MSVC++ int и long являются 32-битными: msdn.microsoft.com/en-us/library/3b2e7499.aspx. Однако, чтобы разрешить, например, векторы для хранения более 4G элементов, size_t - 64 бит. Поэтому для итерации нужно использовать int64_t вместо int, например. векторы, которые могут содержать более 4G элементов.

Serge Rogatch 12.06.2015 20:09

В Cygwinsizeof(long) == 8, даже в Windows :-)

rustyx 29.08.2016 16:41

@SergeRogatch они должны использовать size_t или тип итератора для итерации, а не int или int64_t

phuclv 18.04.2017 05:07

@ 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--).

Serge Rogatch 18.04.2017 12:41

Если вы выполняете математические вычисления с указателями (т.е. со значениями size_t, тогда результат должен храниться в переменной типа ptrdiff_t, которая должна быть достаточно большой для хранения такого результата и является типом подписанный именно по этой причине!)

SlySven 31.07.2017 19:00

@rustyx - это компиляторы, а не операционные системы. Cygwin скомпилирован с использованием mingw (порт GCC для Windows) в качестве компилятора. Как и GCC в Linux, он может определять long как 64-битный, однако MSVC++ (компилятор Microsoft) определяет его как 32-битный.

Orion Edwards 07.02.2021 12:51

@OrionEdwards На самом деле речь идет о целевой платформе ABI. Cygwin имеет собственный POSIX-подобный ABI и выбирает более удобную для POSIX модель LLP64, тогда как Mingw придерживается Win32 ABI со своей моделью LP64. По этой причине в GCC в комплекте с Mingw long составляет 32 бита, а в GCC в Cygwin - 64 бита.

rustyx 07.02.2021 14:41

@rustyx Я чувствую, что мы разговариваем друг с другом. Я хочу сказать, что long существует только в мире компилятора и соглашений, которых он ожидает. Когда дело доходит до запуска кода, это просто «По этому адресу 8 байтов», а термины int, long и т. д. Не существуют.

Orion Edwards 11.02.2021 01:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
140
8
194 093
7

Ответы 7

Если вам нужно использовать целые числа определенной длины, вам, вероятно, следует использовать некоторые независимые от платформы заголовки, чтобы помочь вам. 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 будет предполагать, что указатель на один тип не сможет создать псевдоним другого, несмотря на их совпадающие представления].

supercat 19.05.2016 00:53

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

#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, чтобы узнать, насколько велик ваш длинный тип данных.

Andres 16.10.2009 23:26

Конечно, вы правы, это фактически зависит от архитектуры («адресуемая единица хранения данных, достаточно большая, чтобы вместить любой член базового набора символов среды выполнения»), но наиболее часто используемые архитектуры равны 8 битам.

Paul de Vrieze 25.10.2009 23:08

Но OP не спрашивал о компиляторе / платформе его; он спросил конкретно о 64-битной Windows - вероятно, потому что у него не есть удобный доступ к 64-битной системе Windows для тестирования.

Quuxplusone 03.12.2013 03:09

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-битным.

Jonathan Leffler 22.12.2008 19:39

Не забывайте, что это относится только к Си-иш. У других есть более разумные спецификации, где а) разработчику компилятора не разрешается выбирать размер типов данных волей-неволей или б) физическое представление типов данных не "утекает" или в) целые числа всегда бесконечно велики.

Jörg W Mittag 23.12.2008 20:46

Верно, но для тех языков, которые определяют поведение, в первую очередь нет проблемы. Например, в Java есть «длинный», но размер фиксированный (64-битный?) На всех платформах. Так что проблем с переносом на 64-битную машину нет; размер не меняется.

Jonathan Leffler 24.12.2008 10:05

Утверждать, что Alpha была / есть ILP64, неверно. OpenVMS, Tru64 и Linux, работающие на Alpha, - это «просто» LP64.

Daniel Stenberg 16.06.2011 13:25

@Daniel: спасибо за исправление - я обновил ответ более или менее подходящим образом.

Jonathan Leffler 16.06.2011 18:07

вы думаете, что ILP64 будет более популярным, не было бы проще обрабатывать 64-битный тип данных на 64-битном процессоре?

Tom Fobear 15.02.2012 20:28

@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 есть заслуга.

Jonathan Leffler 15.02.2012 20:39

Возможно, это очевидно для вас, ребята, но я думаю, что стоит отметить, что C# использует целые числа, отличные от всего остального. Недавно я столкнулся с проблемой взаимодействия с DLL, поскольку C# использует 64-битные длинные (msdn.microsoft.com/en-us/library/ms173105.aspx).

Compholio 21.02.2013 18:17

@Compholio: Для меня это было совершенно не очевидно, но я не программировал на C#. В Java тоже есть свой набор фиксированных размеров для целых чисел.

Jonathan Leffler 21.02.2013 18:21

@ Джонатан Леффлер, когда вы говорите, что код должен быть изменен для использования 64-битных возможностей, вы имеете в виду ограничение в 2 ^ 32 элемента в массиве? Я предполагаю, что вы все еще можете использовать более 4 ГБ кучи для нескольких распределений, например. Знаете ли вы, есть ли индексы в контейнерах типа массива в реализациях MS контейнеров STL 32 бит?

SmacL 04.06.2013 18:56

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

Jonathan Leffler 04.06.2013 20:37

@JonathanLeffler: На протяжении десятилетий в области микрокомпьютеров char, short и long были типами фиксированного размера с 8, 16 и 32 битами соответственно. Размер int будет 16 на одних платформах и 32 на других, но код, требующий 16-битного типа, может использовать short, а код, требующий 32-битного типа, может использовать long. Колеса отваливаются, только если int становится 64-битным.

supercat 19.05.2016 00:51

Спасибо за объяснение аббревиатур, стоящих за ILP64, LLP64, LP64!

andreee 25.01.2017 17:15

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

deltamind106 03.11.2017 18:20

Если бы вы изобретали C заново сегодня, даже если оглянуться назад на 20:20 и иметь 45-летний опыт работы с C, неясно, что вы сделаете это изменение. Существует много различных типов ЦП, и разумные конструктивные решения для 8-битного или 16-битного ЦП не обязательно будут разумными для 64-битного ЦП. Я считаю, что есть еще несколько систем, в которых размер слова не является степенью двойки; их было намного больше, когда был изобретен C. Стандарт - это договор между разработчиками компилятора и программистами, которые его используют. Если вы будете внимательно следовать правилам, вы сможете написать переносимый код.

Jonathan Leffler 03.11.2017 19:45

@deltamind: Легко сказать в ретроспективе, но изначально C должен был работать на машинах с 18-битными и 15-битными целыми числами и 7-битными символами, которые, к счастью, уже не в моде.

Robin Davies 27.07.2018 15:50

Возможно, стоит упомянуть, что ABI ILP32 в 64-битном режиме - это вещь (например, AArch64 ILP32 и x86-64 Linux x32), поэтому проверка sizeof(size_t) или sizeof(void*), чтобы определить, поддерживаются ли 64-битные целые числа изначально / эффективно, может по-прежнему иметь ложноотрицательные результаты. Я не знаю, называет ли это это моделью LL64 (где только long long 64-битный).

Peter Cordes 13.06.2019 23:11

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


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

Типы данных Windows

Информация также доступна в различных заголовочных файлах 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» обозначает знаковый / беззнаковый.

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

Вы можете проверить это с помощью sizeof(long).

Другие вопросы по теме