Заметил, что размер встроенного типа зависит от платформы компилирования, например:
1) тип "long" на Linux(gcc) имеет размер 4/8 байт для x32/x64 платформы, но на Window(gcc или VS2015) всегда 4 байта!
2) тип "wchar_t" на Linux(gcc) имеет размер 4 байт, но на Window(gcc или VS2015) 2 байта!
например DWORD определён как "typedef unsigned long" и получается что на Linux x64 он будет 8 байт, и это вызывает ошибки.
Здравствуйте, maks1180, Вы писали:
M>размер встроенного типа зависит от платформы компилирования
Это данность. Стандарт определяет минимум битов на тип, не точное значение. Если хочется точного, то есть int8_t, int16_t, int32_t, int64_t.
M>например DWORD определён как "typedef unsigned long" и получается что на Linux x64 он будет 8 байт, и это вызывает ошибки.
Это какая-то виндовая штука. Думаю, определена она будет для совместимости как uint32_t или int32_t.
M>Почему встроенные типы зависят от платформы ?
Так повелось. Смотри data models вот тут: https://en.cppreference.com/w/cpp/language/types
Здравствуйте, maks1180, Вы писали:
M>Почему встроенные типы зависят от платформы ?
Так устроены языки С и С++.
Во-первых, изначальная идея заключалась в том, что тип `int` будет фокальной точкой системы целочисленных типов этих языков и его размер будет совпадать с размером наиболее эффективно поддерживаемого целочисленного типа данной платофрмы, т.е. фактически совпадать с размером слова данной платформы. Ясно, что размер слова может быть разным на разных платформах, что и подразумевает отличия в натуральных размерах типов.
Как вы все знаете, эта здравая идея потом разбилась о рифы глупой и ленивой идеи "бинарной совместимости", в результате чего тип `int` сегодня является 32-битным даже на платформах с 64-битным словом.
Во-вторых, идея заранее заданного фиксированного рзамера каждого типа нежизнеспособна уже потому, что не все платформы поддерживают все размеры. Понимание этого факта и сегодня выливается в то, что библиотечные типы фиксированных размеров, вроде `int16_t`, являются лишь опционально поддерживаемыми.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Во-первых, изначальная идея заключалась в том, что тип `int` будет фокальной точкой системы целочисленных типов этих языков и его размер будет совпадать с размером наиболее эффективно поддерживаемого целочисленного типа данной платофрмы, т.е. фактически совпадать с размером слова данной платформы. Ясно, что размер слова может быть разным на разных платформах, что и подразумевает отличия в натуральных размерах типов.
АТ>Как вы все знаете, эта здравая идея потом разбилась о рифы глупой и ленивой идеи "бинарной совместимости", в результате чего тип `int` сегодня является 32-битным даже на платформах с 64-битным словом.
В случае как минимум x86, SystemZ, MIPS (AFAIR) и частично ARM, int оставили 32-битным — потому что по-прежнему заметная часть операций может выполняться в 32 битах (x86-64 продолжает иметь 32 бита умолчанием для всего кроме адресных операций). В этом смысле, нет чёткого понятия "слово" у этих платформ, его отождествление с размером адреса некорректно.
(Я уж не вспоминаю, что в документации Intel словом продолжают называть 16 бит. На System/Z, MIPS, ARM, слово это 32 бита.)
Поэтому ссылаться на бинарную совместимость тут достаточно бессмысленно. Если бы была строгая бинарная совместимость, то случилось бы как c Windows, где в x86-64 продолжают сохранять long 32-битным — вот это уже точно полная глупость. (Характерно, что эту глупость не повторили в C#, где long 64-битный.)
А у названных — по-прежнему выполняется (частично или полностью) как раз то, что вы говорили:
AT> его размер будет совпадать с размером наиболее эффективно поддерживаемого целочисленного типа данной платофрмы
Для x86-64 это 32 бита, а не 64 (все команды на байт короче).
Для System/Z это 32 бита, а не 64 (большинство команд в 2 и 4 байта, а не G-группа S/390, где 6 байт).
И так далее.
Вот в случае, например, RISC-V уже не так — основной набор команд 64-битный, а 32 бита в RV64 используются ограниченно. Там, возможно, имело бы смысл думать о введении 64-битного int, но действительно сработала (наверняка) идея совместимости с соседними платформами. В любом случае, недостатки этого решения весьма малы.
АТ>Во-вторых, идея заранее заданного фиксированного рзамера каждого типа нежизнеспособна уже потому, что не все платформы поддерживают все размеры. Понимание этого факта и сегодня выливается в то, что библиотечные типы фиксированных размеров, вроде `int16_t`, являются лишь опционально поддерживаемыми.
Не думаю, что можно найти платформу общего назначения, где бы не было int16_t. Даже если операции выполняются в 32- или 64-битном int, этот тип для хранения продолжает использоваться.
Здравствуйте, maks1180, Вы писали:
M>Почему встроенные типы зависят от платформы ?
По определению. Например, long определен стандартом, как удобный для платформы тип, размером не менее 32-х бит (на самом деле, размер задан не битами, а диапазоном значений). А для int гарантируется диапазон значений, соответствующий как минимум 16-и битам, хоть на большинстве популярных платформ он и равен, фактически, 32-м битам.
Почему линух и венда некоторые типы определяет по-разному, вопрос скорее исторический, чем технический.
Здравствуйте, maks1180, Вы писали:
M>Заметил, что размер встроенного типа зависит от платформы компилирования, например: M>1) тип "long" на Linux(gcc) имеет размер 4/8 байт для x32/x64 платформы, но на Window(gcc или VS2015) всегда 4 байта!
M>2) тип "wchar_t" на Linux(gcc) имеет размер 4 байт, но на Window(gcc или VS2015) 2 байта!
M>например DWORD определён как "typedef unsigned long" и получается что на Linux x64 он будет 8 байт, и это вызывает ошибки.
Если это именно виндовый DWORD, это некорректность определения. Он должен быть uint32_t, а вот во что мапится uint32_t уже должно зависеть от платформы. Рекомендую отправить багрепорт.
Но весь код Unix мира, который я вижу и который работает с типами Windows, давно перешёл на явное указание размера.
M>Почему встроенные типы зависят от платформы ?
С, C++ рассчитаны под очень много разных платформ. Стандарт определяет соотношение размеров (char ⊆ short ⊆ int ⊆ long ⊆ long long) и минимальный размер каждого (определён в минимальном размахе крайних значений, но по сути минимум битности: char — 8, short и int — 16, long — 32 и long long — 64).
Дальше действуют рекомендации (de facto, даже если явно не вписаны всякими ISO):
1) Естественная двоичная иерархия размеров приводит к фиксации на 8-16-32-64-128 бит (и не даёт создавать всякие 29 бит, это вам не мир Гарри Поттера).
2) int должен быть меньшим из нативно без сложного урезания поддерживаемым естественно на целевой платформе, а long — бо́льшим.
3) Для современного не-embedded, int должен быть 32 бита, а не 16, потому что все стали хотеть, чтобы в int влезали значения порядка миллионов. GNU явно пишет в своих рекомендациях "мы считаем, что int у́же 32 бит не бывает".
И вот тут возникает проблема как раз с размером long. При адресации N бит обычно есть и типы данных на >=N бит (перекосы сегментной адресации x86, или менее известной в POWER, SystemZ, в которых 16-битный address space number, не считаем). Если 64 бита в адресе, то есть и вычисления на 64 бита. Значит, long должен быть 64 бита. Unix с LP64 моделью — именно так. Дотнет в лице C# — тоже, хоть он и не "светит" реальный размер адреса. Но это естественно несовместимо с 32-битным режимом, где long был 32 бита. Значит, надо переходить к именованным размерам. Именно поэтому в C99 придумали всякие int32_t — чтобы завязывались на них в платформенно-зависимых местах, при сетевом взаимодействии и т.д.
И вот тут возникает вопрос с диверсией от Windows. Вместо, может быть, чуть более сложного на старте, но пути без дурного легаси, там сделали, что в 64 битах long остаётся 32-битным. Пример обзора для программистов. Авторы этого решения, похоже, сделали не только эту чушь — знаменитая статья (тут тоже обсуждалась). Если вы поддерживаете решение, принятое в Windows... мои соболезнования, но согласиться не могу аж никак.
И вдогонку:
M>Почему встроенные типы зависят от платформы ?
Более общая проблема тут в том, что вообще заточка на конкретный размер типа в таких понятиях, как и само наличие чего-то вроде неуточнённого int — это тяжёлое легаси древних средств, мощность которых была в сотни тысяч и в миллионы раз меньше нынешних и в которых какие-то int использовались только от бедности.
Правильная постановка любой задачи должна содержать конкретный диапазон значений, который уже компилятором отображается оптимальным образом на аппаратуру. Например, если у вас температура воздуха от -50 до +80, то так и надо писать, а не думать, int8_t, int или long. Компилятор, в зависимости от требуемых действий, подберёт, как её хранить и обрабатывать. И он должен, если требуется (а, может, и по умолчанию), вставлять проверки корректности операций (например, что у вас при инкременте не случилось переполнения).
По этому пути шли Pascal и сейчас есть Ada, но их сообщество программистов зарезало, IMO, за не-хакерскость в случае Pascal (и за дороговизну средств в случае Ada 1980-х). C и C++ представляют здесь собой тошнотворный гибридный костыль: молчаливое усечение для unsigned и опора на отсутствие нарушений домена для signed. Оба периодически вылазят боком, но по-разному.
Для внешнего общения, конечно, нужны типы с конкретной битностью. Но и для них должно быть гибче, чем просто 8/16/32/64. По этому пути пошёл LLVM, позволяя все размеры от 1 до 2048 бит, и GCC со своими overflow builtins. Осталось дождаться поддержки в мейнстримовых языках. А для внутреннего — вас не должно волновать, что такое int на конкретной платформе, пока хранение и операции выполняются за вас с соблюдением корректности (обеспеченной или при компиляции, или при выполнении).
The God is real, unless declared integer.
Re[2]: размер встроенных типов зависит от платформы
Здравствуйте, Evgeny.Panasyuk, Вы писали:
N>>IMO, за не-хакерскость в случае Pascal
EP>Ну вот такая примитивная и вездесущая штука как динамический массив в Pascal'е только через struct-хак и была доступна.
Да, это не единственное, что было криво в исходном Паскале. Но это исправили в потомках. А вот переход на C вместе с водой выплеснул и ребёнка. Сейчас использование доменных целочисленных типов (диапазоном или набором значений) восстанавливают, но очень медленно, и легаси этому сильно мешает.
Здравствуйте, netch80, Вы писали:
N>Не думаю, что можно найти платформу общего назначения, где бы не было int16_t. Даже если операции выполняются в 32- или 64-битном int, этот тип для хранения продолжает использоваться.
С и С++ широко используются не только на "платформах общего назначения".
Best regards,
Андрей Тарасевич
Re[4]: размер встроенных типов зависит от платформы
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, netch80, Вы писали:
N>>Не думаю, что можно найти платформу общего назначения, где бы не было int16_t. Даже если операции выполняются в 32- или 64-битном int, этот тип для хранения продолжает использоваться.
АТ>С и С++ широко используются не только на "платформах общего назначения".
И сколько таких платформ осталось в реальном доступе и какая часть из них актуальна для текущего обсуждения?
Да, для полной строгости надо было упомянуть сразу, что на самом деле для внутренней работы предназначены варианты least и fast. В отличие от точных типов intN_t, они обязательны начиная с C99 (хотя отсутствие int16_t имеет смысл только там, где или байт в 32 бита, как на Cray, или если байт не 8-битный — таки сколько таких осталось?) Но я не думал, что кто-то всерьёз будет за это цепляться, особенно в контексте данной темы.
И, я так понял, к остальной части возражений нет. Спасибо.
The God is real, unless declared integer.
Re[5]: размер встроенных типов зависит от платформы
N>>>Не думаю, что можно найти платформу общего назначения, где бы не было int16_t. Даже если операции выполняются в 32- или 64-битном int, этот тип для хранения продолжает использоваться.
АТ>>С и С++ широко используются не только на "платформах общего назначения".
N>И сколько таких платформ осталось в реальном доступе и какая часть из них актуальна для текущего обсуждения?
Именно им текущее обсуждение и посвящено.
Что касается фактической актуальности — это не имеет никакого значения. Как только такие платформы потеряют свою актуальность, их поддержка будет убрана из стандарта языка, как это произошло, например, с прямым и обратным кодами в представлении знаковых целых.
А пока нюансы, направленные на поддержку этих платформ, присутствуют в спецификации языка, никаких разглагольствований об их "актуальности" не будет. Все здесь, без единого исключения, незыблемо убеждены в безграничной важности и критической актуальности таких платформ.
Best regards,
Андрей Тарасевич
Re[6]: размер встроенных типов зависит от платформы
Здравствуйте, Андрей Тарасевич, Вы писали:
N>>>>Не думаю, что можно найти платформу общего назначения, где бы не было int16_t. Даже если операции выполняются в 32- или 64-битном int, этот тип для хранения продолжает использоваться. АТ>>>С и С++ широко используются не только на "платформах общего назначения". N>>И сколько таких платформ осталось в реальном доступе и какая часть из них актуальна для текущего обсуждения? АТ>Именно им текущее обсуждение и посвящено.
Что-то я такого не увидел. Упоминались Windows (32, 64 бита) и Linux (аналогично).
Если где-то нет int16_t, то это отсталость некоторых версий конкретного компилятора, исправленная (AFAIK) в последних изданиях.
АТ>Что касается фактической актуальности — это не имеет никакого значения. Как только такие платформы потеряют свою актуальность, их поддержка будет убрана из стандарта языка, как это произошло, например, с прямым и обратным кодами в представлении знаковых целых.
Ну давайте уточним у топикстартера, насколько ему актуальна какая-нибудь PDP-10 с 18-битным словом.
АТ>А пока нюансы, направленные на поддержку этих платформ, присутствуют в спецификации языка, никаких разглагольствований об их "актуальности" не будет. Все здесь, без единого исключения, незыблемо убеждены в безграничной важности и критической актуальности таких платформ.
Здравствуйте, maks1180, Вы писали:
M>Почему встроенные типы зависят от платформы ?
Потому, что хорошего парня Кернигана "сбил с пути и с панталыку" некий Деннис Ритчи, постоянно твердивший "если тебе нужен PL/1, ты знаешь, где его взять". Т.е. не надо заново изобретать уже существующий язык. Но вот как раз размер данных в битах вполне можно было взять в Си из PL/1, где, например, нет никаких long и short, а есть fixed(7), fixed(15), fixed(31), fixed(63) и т.д. и нет проблемы переноса в этом смысле.
Re[4]: размер встроенных типов зависит от платформы
Здравствуйте, netch80, Вы писали:
N>Сейчас использование доменных целочисленных типов (диапазоном или набором значений) восстанавливают, но очень медленно, и легаси этому сильно мешает.
Не надо. Любая попытка в арифметику — и либо лови ассерты, либо засирай код кастами к i32.
Re[5]: размер встроенных типов зависит от платформы
Здравствуйте, T4r4sB, Вы писали:
TB>Здравствуйте, netch80, Вы писали:
N>>Сейчас использование доменных целочисленных типов (диапазоном или набором значений) восстанавливают, но очень медленно, и легаси этому сильно мешает.
TB>Не надо. Любая попытка в арифметику — и либо лови ассерты, либо засирай код кастами к i32.
Это в каком языке? (Rust?) И в какую именно арифметику? И почему i32? Его точно хватит?
Насколько я понял описание ситуации, оно как раз происходит из некорректного определения доменов. Например, если вы складываете два числа типа i8, результат тоже загоняется в i8. Но по-нормальному он должен быть i9. Это если не учитывать семантику конкретного типа. А если учитывать — то она должна определять допустимые действия (как в C можно вычитать два указателя, но нельзя складывать).
Это сложнее писать в коде, конечно, но потом легче искать ошибки.
Можно, конечно, всех проконвертить к чему-то широкому вроде i32, в нём проверять только его ограничения, а затем проверять уже по результату укладки в выходную переменную. Это то, ради чего, возможно, поддерживают integral promotions, и что делает, например, GNAT (полностью его логику не знаю, но в тестах увидел как раз это).
The God is real, unless declared integer.
Re[6]: размер встроенных типов зависит от платформы
Здравствуйте, netch80, Вы писали:
N>Это в каком языке? (Rust?) И в какую именно арифметику? И почему i32? Его точно хватит?
i32 с высокой вероятностью хратит.
N>Насколько я понял описание ситуации, оно как раз происходит из некорректного определения доменов. Например, если вы складываете два числа типа i8, результат тоже загоняется в i8. Но по-нормальному он должен быть i9.
А, ну-ну. Такое тебе ни один язык ещё лет 20 не поддержит. В реальном мире i8+i8=i8. Со всем вытекающим из этого говном.
N>Можно, конечно, всех проконвертить к чему-то широкому вроде i32, в нём проверять только его ограничения, а затем проверять уже по результату укладки в выходную переменную.
Это единственный рабочий способ в реальном мире на текущий момент. А ещё лучше вообще не конвертить, а сразу работать только с более широким типом, а допустимый диапазон проверять непосредственно в месте, где нужен диапазон. Правда, хипстеры будут недовольны, что это работает не так, как их любимые "кхампайл-тхайм инварайанты" (которые на самом деле не работают), ну и хрен с ними.
Здравствуйте, кт, Вы писали:
кт>Потому, что хорошего парня Кернигана "сбил с пути и с панталыку" некий Деннис Ритчи, постоянно твердивший "если тебе нужен PL/1, ты знаешь, где его взять". Т.е. не надо заново изобретать уже существующий язык. Но вот как раз размер данных в битах вполне можно было взять в Си из PL/1, где, например, нет никаких long и short, а есть fixed(7), fixed(15), fixed(31), fixed(63) и т.д. и нет проблемы переноса в этом смысле.
Может так сделано для возможности переноса языка на другие платформы? В те времена 8-битный байт и целочисленные типы, в которых разрядность кратна 8, ещё не были стандартом де-факто. Например — в PDP-8 использовались 12-разрядные слова.