Печать unsigned long long int Тип значения Возвращает странные результаты

У меня есть проблема при использовании функции printf для печати значений типа unsigned long long int

Я не знаю, что случилось. Я использую Dev-Cpp 4.9.9.2 и Visual Studio 2010 Professional (я знаю, что это не компилятор C, но в любом случае хотел попробовать) на Windows 7 Professional 64-bit. Для отображения я использовал модификатор %llu (в соответствии с Как вы печатаете unsigned long long int (спецификатор формата для unsigned long long int)?), но я также попробовал I64d без эффекта...


Во-первых, я просто хотел напечатать минимальное и максимальное значение unsigned long long int (используя ULONG_MAX from limits.h)

printf("unsigned long long int: \n%llu to %llu \n\n", 0, ULONG_MAX);

Возврат:

unsigned long long int: 18446744069414584320 - 1580552164021 (Dev-Cpp)

unsigned long long int: 18446744069414584320 - 0 (Visual Studio)


Затем я попытался использовать printf для печати двух нулей

printf("unsigned long long int: \n%llu to %llu \n\n", 0, 0);

Возврат:

unsigned long long int: 0 до 1580552164021 (Dev-Cpp)

unsigned long long int: от 0 до 0 (Visual Studio)


Также были проверены два значения ULONG_MAX

printf("unsigned long long int: \n%llu to %llu \n\n", ULONG_MAX, ULONG_MAX);

Возврат:

unsigned long long int: 18446744073709551615 - 1580552164021 (Dev-Cpp)

unsigned long long int: 18446744073709551615 - 0 (Visual Studio)


Почему он ведет себя так? Не могли бы вы объяснить это мне?

Ответ 1

Это неправильно:

printf("unsigned long long int: \n%llu to %llu \n\n", 0, ULONG_MAX);

Вы используете спецификатор формата unsigned long long, но вы передаете значение int и unsigned long. Правила продвижения означают, что вы можете быть sloppy для всего int -размер или меньше, что не относится к long long.

Использовать трансляции:

printf("unsigned long long int: \n%llu to %llu \n\n",
       0ULL, (unsigned long long) ULONG_MAX);

Объяснение: При передаче аргументов в printf любой тип, который может поместиться в int, продвигается до int, а затем любой тип, который может поместиться в unsigned int, повышается до unsigned int. Также можно передать тип unsigned в спецификатор подписанного формата или наоборот, если переданное значение может быть представлено с использованием типа, указанного спецификатором формата.

Итак, вы должны быть осторожны с long и long long, но вы можете быть неаккуратными с int, short и char.

Большинство компиляторов имеют настройки, чтобы заставить их предупреждать вас об этом типе ошибок, поскольку его можно легко обнаружить во время компиляции; GCC и Clang имеют -Wformat, что приводит к следующим предупреждениям:

test.c:5: warning: format ‘%llu’ expects type ‘long long unsigned int’, but argument 2 has type ‘int’
test.c:5: warning: format ‘%llu’ expects type ‘long long unsigned int’, but argument 3 has type ‘long unsigned int’

Ответ 2

Вы не проходите unsigned long longs. Вы передаете int (0) и unsigned long (ULONG_MAX). Вы должны передать printf() то, что вы обещаете передать в строке формата.

Попробуйте это вместо:

printf("unsigned long long int: \n%llu to %llu \n\n", 0ULL, (unsigned long long)ULONG_MAX);

Ответ 3

ULONG_MAX относится к unsigned long, а не к unsigned long long. Для последнего используйте ULLONG_MAX (обратите внимание на дополнительный L).

Вам нужно изменить вызовы printf() следующим образом:

printf("unsigned long long int: \n%llu to %llu \n\n", 0ULL, ULLONG_MAX);
printf("unsigned long long int: \n%llu to %llu \n\n", ULLONG_MAX, ULLONG_MAX);

Это гарантирует, что аргументы printf() соответствуют спецификаторам формата.

Ответ 4

long long int - это тип из стандарта C99, MSVC не поддерживает это. Возьмите компилятор с поддержкой C99 (например, MinGW для Windows), и он будет работать.