Ответ 1
Попробуйте 285212672ULL
; если вы напишете его без суффиксов, вы обнаружите, что компилятор рассматривает его как регулярное целое число. Причина, по которой она работает в переменной, состоит в том, что целочисленное значение передается в unsigned long long
в присваивании, так что значение, переданное в printf()
, является правильным типом.
И прежде чем вы спросите, нет, компилятор, вероятно, недостаточно умен, чтобы понять это из "%llu
"в строке формата printf()
. Это другой уровень абстракции. Компилятор отвечает за язык синтаксис, printf()
семантика не является частью синтаксиса, это функция библиотеки времени выполнения (не отличается от ваших собственных функций, кроме того, что она включена в стандарт).
Рассмотрим следующий код для 32-битной int и 64-битной беззнаковой длинной длинной системы:
#include <stdio.h>
int main (void) {
printf ("%llu\n",1,2);
printf ("%llu\n",1ULL,2);
return 0;
}
который выводит:
8589934593
1
В первом случае два 32-разрядных целых числа 1 и 2 помещаются в стек, а printf()
интерпретирует это как одно 64-битное значение ULL, 2 x 2 32 + 1. Аргумент 2
непреднамеренно включается в значение ULL.
Во втором вы фактически нажимаете 64-битное 1-значение и избыточное 32-разрядное целое число 2
, которое игнорируется.
Обратите внимание, что это "выход из строя" между вашей строкой формата и вашими фактическими аргументами - плохая идея. Что-то вроде:
printf ("%llu %s %d\n", 0, "hello", 0);
скорее всего, произойдет сбой, потому что 32-разрядный указатель "hello"
будет потребляться %llu
и %s
попытается снять ссылку с конечного аргумента 0
. Это иллюстрирует следующий "рисунок" (предположим, что ячейки 32 бита и что строка "hello" хранится в 0xbf000000.
What you pass Stack frames What printf() uses
+------------+
0 | 0 | \
+------------+ > 64-bit value for %llu.
"hello" | 0xbf000000 | /
+------------+
0 | 0 | value for %s (likely core dump here).
+------------+
| ? | value for %d (could be anything).
+------------+