Подтвердить что ты не робот

В чем причина явного объявления L или UL для длинных значений

Из примера

unsigned long x = 12345678UL

Мы всегда узнали, что компилятор должен видеть только "длинный" в приведенном выше примере, чтобы установить 4 байта (в 32 бит) памяти. Вопрос в том, почему мы должны использовать L/UL в длинных константах даже после объявления его длинным.

4b9b3361

Ответ 1

Когда суффикс L или UL не используется, компилятор использует первый тип, который может содержать константу из списка (см. подробности в стандарте C99, раздел 6.4.4: 5. Для десятичной константы, список int, long int, long long int).

Как следствие, в большинстве случаев нет необходимости использовать суффикс. Это не меняет смысл программы. Это не изменяет значение инициализации вашего примера x для большинства архитектур, хотя это было бы, если бы вы выбрали число, которое не могло бы быть представлено как long long. См. Также ответ codebauer для примера, где необходима часть U суффикса.


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

printf("%lld", 1LL); // correct
printf("%lld", 1);   // undefined behavior

Общей причиной использования суффикса является то, что результат вычисления не переполняется. Два примера:

long x = 10000L * 4096L;
unsigned long long y = 1ULL << 36;

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

Как утверждает Lightness Races в Orbit, суффикс litteral имеет значение до. В двух приведенных выше примерах просто объявить x как long и y как unsigned long long недостаточно для предотвращения переполнения при вычислении выражений, назначенных им.


Другим примером является сравнение x < 12U, где переменная x имеет тип int. Без суффикса U компилятор задает константу 12 как int, и поэтому сравнение представляет собой сравнение подписанных int.

int x = -3;
printf("%d\n", x < 12); // prints 1 because it true that -3 < 12

С суффиксом U сравнение становится сравнением беззнаковых int. "Обычные арифметические преобразования" означают, что -3 преобразуется в большой беззнаковый int:

printf("%d\n", x < 12U); // prints 0 because (unsigned int)-3 is large

Фактически, тип константы может даже изменить результат арифметического вычисления, опять же из-за того, как работают "обычные арифметические преобразования".


Обратите внимание, что для десятичных констант список типов, предложенный C99, не содержит unsigned long long. В C90 список завершился самым большим стандартизованным целым типом без знака в то время (который был unsigned long). Следствием было то, что значение некоторых программ было изменено путем добавления стандартного типа long long к C99: та же самая константа, которая была набрана как unsigned long в C90, теперь может быть введена как подписанная long long. Я считаю, что именно по этой причине в C99 было принято решение не иметь unsigned long long в списке типов для десятичных констант. Для примера см. this и . p >

Ответ 2

Поскольку числовые литералы типичны для типа int. UL/L сообщает компилятору, что они не имеют тип int, например. предполагая 32-битный int и 64-битный длинный

long i = 0xffff;
long j = 0xffffUL;

Здесь значения справа должны быть преобразованы в подписанные longs (32 бит → 64 бит)

  • "0xffff", int, преобразуется в длинное расширение знака, что приводит к отрицательному значению (0xffffffff)
  • "0xffffUL", без знака long, будет преобразован в длинный, что приведет к положительному значению (0x0000ffff)

Ответ 3

Вопрос в том, почему мы должны использовать L/UL в длинных константах даже после объявления его длинным.

Потому что это не "после"; это "раньше".

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

Ответ 4

В связи с этим сообщением почему a u.

Причиной для u является разрешение целочисленной константы больше LLONG_MAX в десятичной форме.

// Likely to generate a warning.
unsigned long long limit63bit = 18446744073709551615`; // 2^64 - 1

// OK
unsigned long long limit63bit = 18446744073709551615u`;