printf size_t переменной с lld, ld и d идентификаторами типов

Я написал этот крошечный код:

#include <stdio.h>
int main() {
    size_t temp;
    temp = 100;

    printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp);

    return 0;
}

Я выполняю это на i386 машине GNU/Linux с gcc версией 4.1.1 20070105 (Red Hat 4.1.1-52). Это - вывод, который я получил:

lld=429496729700, ld=100, u=7993461

Я могу понять что первое (lld) был распечатан как мусор потому что printf попытки распечатать 8 байтов (для signed long long как показано lld) когда только 4 байта доступны от переменной temp. Но, мне не удается понять почему последний идентификатор, u становится печатным как мусор - тогда как, в моем понимании это - самый близкий применимый идентификатор для size_t.

Здесь я принял это size_t unsigned int (который подписывается 4 байта для моего i386).

Теперь, я сделал немного тонкой настройки с printf строка:

...
printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp);
...

и у меня есть превосходный ответ (кроме lld часть).

ld=100, u=100, lld=34331653576851556

Кто-то может помочь мне в понимании, что точно я пропускаю здесь?

Большое спасибо за любую справку!

[примечание стороны: Я пытался переключить использование оптимизации gcc -O[0,2] отметьте вкл\выкл без любого различия в наблюдении.]

12
задан Shrey 11 March 2010 в 11:37
поделиться

3 ответа

Это потому, что вы поместили в стек три 32-битных значения, и ваша строка формата пытается использовать четыре из них или, точнее, одно 64-битное значение и два 32-битных значения.

В первом случае lld поглощает два 32-битных значения, ld поглощает третье, а u получает все, что происходит с быть в стеке после этого, что действительно может быть чем угодно.

Когда вы меняете порядок описателей формата в строке, он работает по-другому, потому что ld поглощает первое 32-битное значение, u поглощает второе и lld засасывает третий плюс все, что окажется в стеке после этого. Вот почему вы получаете разные значения, это проблема согласования / доступности данных.

Вы можете увидеть это в действии с первым значением. 429496729700 равно (4294967296 + 1) * 100 , то есть (2 32 +1) * 100. Ваш фрагмент кода

printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp);

на самом деле имеет следующий эффект:

What you pass     Stack     What printf() uses
-------------     -----     ------------------
                 +-----+
100              | 100 | \
                 +-----+  = 64-bit value for %lld.
100              | 100 | /
                 +-----+
100              | 100 |    32-bit value for %ld.
                 +-----+
                 | ?   |    32-bit value for %u (could be anything).
                 +-----+

Во втором случае

printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp);

происходит следующее:

What you pass     Stack     What printf() uses
-------------     -----     ------------------
                 +-----+
100              | 100 |    32-bit value for %ld.
                 +-----+
100              | 100 |    32-bit value for %u.
                 +-----+
100              | 100 | \
                 +-----+  = 64-bit value for %lld (could be anything).
                 | ?   | /
                 +-----+
23
ответ дан 2 December 2019 в 04:43
поделиться

Ваш код точно демонстрирует неопределенное поведение. Обратите внимание, что в случае вариативных аргументов проверка типов для параметров не выполняется. Это когда явное приведение становится необходимым. Фактически, поэтому следует использовать следующее:

 printf("lld=%lld, ld=%ld, u=%u\n", 
         (unsigned long long)temp, 
         (unsigned long)temp, 
         (unsigned int)temp);

Напомним, что спецификатор для size_t - z . Итак:

 printf("zd=%zd\n", temp);
9
ответ дан 2 December 2019 в 04:43
поделиться

Вы передаете printf неправильное количество байтов. % lld требует большего целого числа, в вашем случае способ, которым% lld использовал свой аргумент, полностью испорчен, так как он ожидал бы 64-битное значение.

0
ответ дан 2 December 2019 в 04:43
поделиться
Другие вопросы по тегам:

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