Гарантируется ли (uint64_t) -1 0xffffffffffffffff?

Я знаю, что это хорошо определено стандартом C, что (unsigned)-1 должен дать 2 ^ n-1, т.е. е. целое число без знака со всеми установленными битами. То же самое касается (uint64_t)-1ll, Тем не менее, я не могу найти что-то в стандарте C11, который определяет, как (uint64_t)-1 интерпретируется.

Итак, вопрос: есть ли какая-либо гарантия в стандарте C, что из следующего верно?

(uint64_t)-1 == (uint64_t)(unsigned)-1   //0x00000000ffffffff
(uint64_t)-1 == (uint64_t)(int64_t)-1    //0xffffffffffffffff

13

Решение

Да. См. C11 6.3.1.3 Целые числа со знаком и без знака:

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

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

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

60) Правила описывают арифметику математического значения, а не значения данного типа выражения.

Случай 2 применяется, поэтому -1 уменьшается по модулю 0x10000000000000000, чтобы получить 0xffffffffffffffff.

14

Другие решения

Выражения 1 а также -1 иметь тип int, Когда преобразовано в uint64_tПринцип 2N складывается или вычитается, пока не будет применено значение в диапазоне, поэтому результат всегда равен 2N-1, в этом случае с n = 64. Следовательно, (uint64_t)-1 всегда 264-1 ..

Выражение (int64_t)-1 оценивается как -1, поэтому то же самое рассуждение применимо к выражению (uint64_t)(int64_t)-1, который тоже всегда оценивается в 264-1.

С другой стороны, (unsigned)-1 является положительным значением типа unsigned int это может быть 216-1, 232-1, 264-1 или различные другие значения в зависимости от платформы компиляции. Эти значения могут не дать 264-1 при конвертации в uint64_t,

5

Я предполагаю, что ты пишешь (uint64_t)-1 вместо -1ULL потому что вы не хотите делать предположения о размере unsigned long long? Если так, это хорошо. Тем не менее, есть альтернатива, которая еще не была упомянута (и на самом деле не отвечает на ваш вопрос), но может избавить вас от многих беспокойств, обойдя вопрос стороной:

Альтернатива

Хорошая привычка всегда использовать UINT64_C(x) вместо (uint64_t)x, Это макрос, определенный в <stdint.h> который автоматически добавляет U, UL, или же ULL по мере необходимости. Таким образом, UINT64_C(-1) решает либо -1U, -1UL, или же -1ULLв зависимости от вашей цели. Это гарантированно всегда работает правильно.

Опасности литья типов

Обратите внимание, что (uint64_t)x на самом деле даже не работает правильно в целом. Например,

(uint64_t)2147483648                // RISKY

генерирует предупреждение на некоторых компиляторах, потому что значение 2147483648 (2 ^ 31) слишком велико, чтобы поместиться в 32-разрядное целое число, а следующее даже удаленно не работает:

(uint64_t)1000000000000000000       // RISKY

Однако, если вы используете UINT64_C() вместо этого тогда все золотое

UINT64_C(2147483648)                // GOOD

UINT64_C(1000000000000000000)       // GOOD

UINT64_C(-1)                        // GOOD

Заметки:

  • _C суффикс означает «постоянный».
  • В <stdint.h> Существуют также 8-, 16- и 32-разрядные версии для значений со знаком и без знака.
  • Для особого случая –1 вы также можете просто написать UINT64_MAX,
2

На этот вопрос можно ответить с помощью нескольких строк кода.

#include <stdio.h>

main()
{
int          x;
unsigned int y;

x = -1;
printf("\n0x%08x", x);

y = (unsigned int) -1;
printf("\n0x%08x", y);

}

Запуск этого кода на компиляторе Eclipse / Microsoft C приводит к:

0xffffffff
0xffffffff

Подобная программа может показать вам, что uint64_t производит.

Наконец, если вы понимаете, как компьютеры используют числа дополнения 2 для добавления чисел, то вы поймете, что -1 для слов любого количества битов (8, 32, 64 и т. Д.) Всегда все ff для каждого байта в слове / двойное слово и т. д.

-5