Непоследовательные результаты printf с long long int?

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 требуют , чтобы вы сообщали компилятору точно, какие типы следуют.