Я написал этот крошечный код:
#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]
отметьте вкл\выкл без любого различия в наблюдении.]
Это потому, что вы поместили в стек три 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).
| ? | /
+-----+
Ваш код точно демонстрирует неопределенное поведение. Обратите внимание, что в случае вариативных аргументов проверка типов для параметров не выполняется. Это когда явное приведение становится необходимым. Фактически, поэтому следует использовать следующее:
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);
Вы передаете printf неправильное количество байтов. % lld требует большего целого числа, в вашем случае способ, которым% lld использовал свой аргумент, полностью испорчен, так как он ожидал бы 64-битное значение.