struct DummyStruct{ unsigned long long std; int type; }; DummyStruct d; d.std = 100; d.type = 10; /// buggy printf, unsigned long long to int conversion is buggy. printf("%d,%d\n",d.std, d.type); // OUTPUT: 0,100 printf("%d,%d\n", d.type, d.std); // OUTPUT: 10,100 printf("%lld,%d\n",d.std, d.type); // OUTPUT: 100,10
Скажите, пожалуйста, почему unsigned long long to int conversion неправильно обрабатывается в printf. Я использую glibc.
Это ошибка в printf?
почему printf не выполняет преобразование внутреннего типа?
Это ваше использование, которое является проблемой. Если типы, указанные в строке формата, точно такие же, как типы в параметрах, тогда все будет работать неправильно.
Это связано с тем, что компилятор подталкивает параметры как есть в стек.
Нет проверки типа или преобразования.
Во время выполнения код вытягивает значения стека и переходит к следующему объекту на основе значения в строке формата. Если строка формата ошибочна, то указанная сумма неверна, и вы получите забавные результаты.
Аргумент %d
указывает printf
интерпретировать соответствующий аргумент как int
. Попробуйте использовать %llu
long long
. И запомните эту справочную карту .
(Нет, это не ошибка)
Правило первое: вероятность того, что вы обнаружите ошибку в библиотеке или компиляторе, очень и очень тонкая. Всегда предполагайте, что компилятор / библиотека права.
Параметры передаются printf()
через механизмы в
(списки переменных аргументов), что связано с некоторой магией в стеке.
Не вдаваясь в подробности, что делает printf()
, предполагается, что следующий параметр, который он должен извлечь из стека, имеет тип, указанный в вашей строке формата – в случае %d
– подписанный int .
Это работает, если фактическое значение, которое вы указали там, меньше или равно по ширине для int
, потому что внутри любое меньшее значение, переданное в стек, расширяется до ширины int
через механизм, называемый « целая продвижение ».
Однако это не удается, если тип, который вы передали printf()
, больше, чем int
: printf()
сообщается (вашим %d
), чтобы ожидать int
и вытягивает соответствующее количество байтов (предположим, что 4 байта для 32 бит int
) из стека.
В случае вашего long long
, которое мы предположим, это 8 байтов для 64-битного значения, это приводит к тому, что printf()
получает только половину вашего long long
. Остальное по-прежнему находится в стеке и даст довольно странные результаты, если вы добавите еще один %d
в строку формата.
😉
С printf (который является одной из очень старых функций из оригинального C) компилятор не передает параметры после списка формата в нужный тип, т. Е. Вам нужно убедиться, что типы в списке параметров совпадают с типами в списке параметров формат.
С большинством других функций компилятор сжимает данный параметр в объявленные типы, но printf, scanf и friends требуют , чтобы вы сообщали компилятору точно, какие типы следуют.