C: Печать больших чисел

Это говорит компилятору не жаловаться на неизвлеченную строку, и что это не требует локализации.

11
задан Andreas Grech 8 September 2009 в 11:52
поделиться

4 ответа

Попробуйте 285212672ULL ; если вы напишете его без суффиксов, вы обнаружите, что компилятор рассматривает его как обычное целое число. Причина, по которой он работает с переменной, заключается в том, что целое число приводится к unsigned long long в присваивании, поэтому значение, переданное в printf () , является правильным типом.

И прежде чем вы спросите, нет, компилятор, вероятно, не достаточно умен, чтобы вычислить это из "% llu " в printf () форматная строка. Это другой уровень абстракции. Компилятор отвечает за синтаксис языка, семантика printf () не является частью синтаксиса , это функция библиотеки времени выполнения (ничем не отличается от ваших собственных функций, за исключением того, что она ' s включены в стандарт).

Рассмотрим следующий код для 32-разрядной системы int и 64-разрядной системы long long без знака:

#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-битный "привет" Указатель будет использован аргументом % llu , а % s попытается отменить ссылку на последний аргумент 0 . Следующее «изображение» иллюстрирует это (предположим, что ячейки являются 32-битными, а строка «привет» хранится по адресу 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).
                 +------------+
25
ответ дан 3 December 2019 в 02:20
поделиться

285212672 - это значение int . printf ожидает unsigned long long , а вы передаете ему int . Следовательно, это займет больше байтов из стека, чем вы передали реальное значение, и распечатает мусор. Когда вы помещаете его в переменную unsigned long long перед передачей в функцию, он будет повышен до unsigned long long в строке присваивания, и вы передадите это значение в ] printf , который работает правильно.

3
ответ дан 3 December 2019 в 02:20
поделиться

Стоит отметить, что некоторые компиляторы дают полезное предупреждение для этого случая - например, это то, что GCC говорит о вашем коде:

x.c: In function ‘main’:
x.c:6: warning: format ‘%llu’ expects type ‘long long unsigned int’, but argument 2 has type ‘int’
5
ответ дан 3 December 2019 в 02:20
поделиться

Тип данных - это просто способ интерпретации содержимого ячейки памяти.
в первом случае постоянное значение сохраняется в ячейке памяти только для чтения как int, printf пытается интерпретировать этот адрес как 8-байтовую ячейку, поскольку получает указание, что сохраненное значение является long long, в процессе чего он печатает значение мусора.
Во втором случае printf пытается интерпретировать длинное длинное значение как 8 байтов и печатает то, что ожидается.

0
ответ дан 3 December 2019 в 02:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: