printf переменной size_t с идентификаторами типов lld, ld и d - PullRequest
12 голосов
/ 11 марта 2010

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

#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 (что для моего i386 подписано 4 байта).

Теперь я немного изменил строку printf:

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

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

ld=100, u=100, lld=34331653576851556

Может кто-нибудь помочь мне понять, что именно мне здесь не хватает?

Большое спасибо за любую помощь!

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

Ответы [ 3 ]

23 голосов
/ 11 марта 2010

Это потому, что вы поместили в стек три 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).
                 | ?   | /
                 +-----+
9 голосов
/ 11 марта 2010

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

 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);
0 голосов
/ 11 марта 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...