LINUX.ORG.RU

Стандартен ли long в Си?

 , ,


0

2

Собственно вопрос. Описаны ли стандартом размеры всяких

long
long long
int
double
// И так далее

?
Если описаны, то чему равны их размеры? Или это компиляторозависимая платформоспецифичная особенность и лучше использовать к примеру uint64_t?

★★☆
  1. Да, описаны.

  2. У этих типов в стандарте нет фиксированного размера, есть требование на их минимальный размер.

  3. Типы с фиксированным размером лучше использовать там, где нужен фиксированный размер.

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

PS: возьми, да прочитай: http://libgen.rs/search.php?req=ISO%2FIEC+9899&open=0&res=25&view=simple&phrase=1&column=def

soomrack ★★★★★
()
Последнее исправление: soomrack (всего исправлений: 1)
Ответ на: комментарий от soomrack

тогда у компилятора остается больше возможностей для оптимизации

Причём это гарантируется (там же):

  • int (also accessible as signed int) - This is the most optimal integer type for the platform, and is guaranteed to be at least 16 bits.
raspopov
()

В стандарте Си не описано.

Но для каждой платформы есть жестко заданные ABI, например System V ABI для x86-64 - и надо ориентироваться на них

lovesan ★★★
()

Или это компиляторозависимая платформоспецифичная особенность и лучше использовать к примеру uint64_t?

нет никакого единого рецепта или универсальной рекомендации, надо думать самому. Определись с требованиями, которые ты предъявляешь в конкретной задаче, и посмотри, какой тип им удовлетворяет.

Lrrr ★★★★★
()
Ответ на: комментарий от raspopov

Причём это гарантируется (там же)

Чего гарантируется, где? На cppreference? Это свободный для редактирования проект типа википедии, куда каждый пишет свои фантазии о C++. Что там может «гарантироваться»?

utf8nowhere ★★★
()
Ответ на: комментарий от Waterlaz

Не похоже

А вы заметьте, красивая табличка как оно по битам располагалось приведена для только 32 бита, что оно там для 64 даже не нашли документацию :) Оно, конечно, для отдельного сопроцессора может и поддерживалось внутри, но для C было доступно только float как 16 бит нативно или для double 32 bit как либо програмной эмуляцией либо отдельным сопроцессором, что ещё не во всех моделях pdp-11 был.

vodz ★★★★★
()

Размеры примитивных целочисленных типов на практике выбираются с потолка каждым компилятором во многом исходя из исторических соображений и поддержки старой кодовой базы где код предполагает определённый размер примитивных типов. Примитивные типы Си на современных компиляторах/железе не означают наиболее оптимальный выбор для конкретного железа. Вероятно когда-то этот выбор был оптимальным, но теперь уже нет в результате перехода на 64 битную архитектуру и т.п.. Но есть много старого кода который рассчитывает что например long должен быть 32 битный. Недавно Wine по этому поводу рефакторили.

Так что лучше забыть про short, int, long, и пользоваться int32_t и т.п..

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 2)
Ответ на: комментарий от wandrien

Они даже в разных компиляторах для одной платформы могут различаться. Например MSVC vs GCC под Windows. Базовый ABI тот же (порядок передачи аргументов в регистрах/на стеке и т.п.), а размер типа long разный.

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Ответ на: комментарий от wandrien

Да, если работаешь с API, которое использует int и т.п., то в коде непосредственно взаимодействующим с этим API разумно использовать тот же самый тип.

X512 ★★★★★
()
Ответ на: комментарий от X512

Имхо, исторический баг. Так делать не надо.

А мне вот, кстати, очень интересно, почему в Linux ABI соглашение о возврате результата на x86 отличается от соглашения BSD. Кто из них пошел по пути NIH?

wandrien ★★★
()
Ответ на: комментарий от wandrien

А мне вот, кстати, очень интересно, почему в Linux ABI соглашение о возврате результата на x86 отличается от соглашения BSD. Кто из них пошел по пути NIH?

А я вот вдогонку спрошу, почему на x86_64 аргументы в системные вызовы передаются через регистры не в том порядке, как для функций?

Waterlaz ★★★★★
()
Ответ на: комментарий от X512

поддержки старой кодовой базы

Разработчики компиляторов так часто «ломали» совместимость со своей же старой версией, что логичнее предположить, что это не имеет для них особого значения. 😎

Но есть много старого кода который рассчитывает что например long должен быть 32 битный

🤦‍♂️ По стандарту long не менее чем 32-битный.

И не надо думать, что разработчики ПО не в курсе, что лучше использовать sizeof(long), чем 4.

raspopov
()
Ответ на: комментарий от raspopov

Кстати в статье https://barrgroup.com/embedded-systems/how-to/c-fixed-width-integers-c99

советуется делать анонимное объединение

static union
{
    char   int8_t_incorrect[sizeof(  int8_t) == 1];
    char  uint8_t_incorrect[sizeof( uint8_t) == 1];
    char  int16_t_incorrect[sizeof( int16_t) == 2];
    char uint16_t_incorrect[sizeof(uint16_t) == 2];
    char  int32_t_incorrect[sizeof( int32_t) == 4];
    char uint32_t_incorrect[sizeof(uint32_t) == 4];
};

Listing 2. This anonymous union allows a compiler to detect and report typedef errors

Gyros
()

Я придерживаюсь следующих правил:

  1. Если значение переменной передаётся или возвращается в API, то использовать нужный тип. К примеру open() возвращает int.

  2. Если нужен гарантированный размер (это нужно редко) - использовать что-то вроде int8_t. Но надо понимать, что гарантии доступности всех этих типов нет и программа может не скомпилироваться.

  3. В остальных случаях использовать что-то вроде int_fast8_t или int_least8_t в зависимости от того, нужна скорость или малое потребление памяти.

  4. Естественно в нужных местах нужно использовать uintptr_t, size_t, ptrdiff_t и тд.

В целом использовать char, short, int, long и тд считаю плохим тоном, кроме как для использования внешних API. Типы из stdint имеют куда более понятную семантику.

vbr ★★★★★
()
Последнее исправление: vbr (всего исправлений: 2)
Ответ на: комментарий от MKuznetsov

только double - 64 бит и совершенно одинаковый везде.

Не совсем правда. Не очень актуально нынче, но во времена x87ых co-processors с их внутренним 80ти битным представлением запросто можно было нарваться на очень интересные нюансы. Причём с зависимостью результата от уровня оптимизаций, а если точнее - от того произошла выгрузка в память с округлением до 64ёх бит, или нет.

bugfixer ★★★★★
()
Ответ на: комментарий от raspopov

Разработчики компиляторов так часто «ломали» совместимость со своей же старой версией, что логичнее предположить, что это не имеет для них особого значения. 😎

Злостное 4.2. На моей памяти слом ABI происходил пару раз, с довольно быстрыми фиксами.

Или у Вас конкретные мозоли^W контр-примеры имеются?

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

контр-примеры имеются?

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

Но если хочется, то: https://youtu.be/kJSXhZzEyZU

raspopov
()
Ответ на: комментарий от raspopov

Тут настолько ясная ситуация

Нет, так дело не пойдёт.

что ничего доказывать не нужно

Не нужно, одного конкретного примера будет достаточно. Желательно в форме ссылки на багзиллу gcc.

Сразу оговорюсь что «компилировалось и перестало» - не прокатит. Нужно или silent change in behavior not involving UB, или «старые билды не работают с новым runtime».

А до тех пор то что Вы заявили выглядит как гнусный поклёп на gcc dev’ов.

Но если хочется, то: https://youtu.be/kJSXhZzEyZU

Издеваетесь? Видео больше чем на час с докладом какой-то девочки? И спонсоры там тоже очень интересные. Я уже молчу про тему доклада, которая в такой формулировке вызывает серьезные сомнения в профессионализме девочки.

bugfixer ★★★★★
()
4 июля 2023 г.
Ответ на: комментарий от soomrack

потому как тогда у компилятора остается больше возможностей для оптимизации

а еще бы я добавил, что типов некоторых размеров может вообще не быть на платформе — и тогда будет ошибка компиляции и надо будет редактировать код...

safocl ★★
()
Ответ на: комментарий от safocl

Сложную программу один хрен надо будет специально портировать под другую платформу, а не только перекомпилировать. Так, что ошибка компиляции это даже неплохо. Хуже, если нормально скомпилировалось, а потом баги надо ловить.

praseodim ★★★★★
()
Ответ на: комментарий от praseodim

эмм... это какими же ты костылями пользуешься что у тебя на другой платформе надо чото переделывать?

ты же пишешь на языке программирования, а не на платформокоде....

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

по сути единственный язык программирования на котором надо писать заново — ассемблера.

safocl ★★
()
Последнее исправление: safocl (всего исправлений: 3)
Ответ на: комментарий от raspopov

И не надо думать, что разработчики ПО не в курсе

Ну это смотря какие разработчики, мне как-то пришлось патчить проект, в котором предполагалось, что sizeof(void*)==sizeof(int)

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от safocl

эмм... это какими же ты костылями пользуешься что у тебя на другой платформе надо чото переделывать?

Да практически любая программа, заметно посложнее helloworld, выйдет зависимой от платформы. Особенно, если код быстрый и оптимизированный.

Никто не пишет, имея при этом в виду все разнообразие железа, даже экзотического. Явно или неявно, но вылезет что-то платформенное. Более того, на практике, если код предназначен для разных платформ, его или IFDEF-ами обкладывают и/или разные файлы используют при сборке.

А вылезти может вообще туева хуча всего - и размер типов и порядок байт и выравнивание и все это для кросплатформы надо учесть при работе с данными. И даже такие вещи, что не везде есть пользовательский аппаратный стек, к примеру. Не говоря о том, что для разных платформ может не быть единого компилятора вообще и просто-напросто часть возможностей языка отсутствовать.

praseodim ★★★★★
()
Последнее исправление: praseodim (всего исправлений: 3)

char = 1 байт гарантированно. Далее

char(1)<=short(1 или 2)<=int(2 или 4)<=long(4 или 8)<=long long(4 или 8 (в теории ещё или 4 или 8 или 16))

Часто справедливо char(1) short(2) int(4) long(8) long long(синоним long)

float = 4 байта гарантированно IEEE-754 double == 8 байт гарантированно IEEE-754 (даже на 8 битном микроконтроллере)

Определяется всё на конкретной платформе по типу INT_MIN/INT_MAX/etc для каждого из типов.

cat /usr/include/limits.h На твоей целевой машине и это самое важное =)

На всяких risc-v есть железная 128 битная адресация, там есть по сути long long long или просто uint128_t его при желании можно и на 64битной системе получить на обычном x86_64.

Гарантия размеров есть для трёх типов, вся остальная гарантия это гарантия того кто больше или равен другому. Ну, а если тебе нужны именно точные размеры то typenameXX_t к твоим услугам, как это разруливать уже будет задача компилятора.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от bugfixer

Ну это старые подколы школьных времен, впрочем, этим подколам скорее всего столько же лет, сколько и языку.

Сейчас они не сработают, IDE или компиляторы будут ругаться на такое.

soomrack ★★★★★
()
Ответ на: комментарий от nionio35

почему же. делаю так.

Это пройдёт.

ПыСы. Ну, и что - хоть раз пригодилось? Имеется в виду - алиас поправили и всё даже «заработало» после этого?

и не я один.

Хех… Куда катится этот мир…

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 2)
Ответ на: комментарий от nionio35

нужно два варианта программы, один с 64 int, второй c 32 int.

Я готов поверить что это может быть нужно для маленького кусочка программы. Другими словами - алиасится тип с узкой и конкретной областью применения. Например typedef int32_t fieldX_t. Это бы ещё имело хоть какой-то смысл. А алиасить инты глобально - так себе затея.

bugfixer ★★★★★
()
Ответ на: комментарий от nionio35

нужно два варианта программы, один с 64 int, второй c 32 int. в одном файле все указал. при компиляции выставил флаг и все.

А что это за программа такая, что смена 64 на 32 ее не ломает, а использование обычного long int – сломает?

soomrack ★★★★★
()