вопрос о несовместимых спецификаторах формата printf

Я просто просматривал справочную страницу для printf, и кое-что пришло мне в голову. Мне было интересно, есть ли здесь «языковые юристы», которые могли бы ответить на относительно простой вопрос :-P.

Таким образом, модификатор 't' определяется как

Следующее целочисленное преобразование соответствует аргументу ptrdiff_t.

Итак, что должно произойти, если вы объедините это с преобразованием целого числа без знака? Очевидно, что все o,u,x и X предназначены для интерпретации как значения без знака, тогда как d и i являются знаковыми.

Точно так же существуют подписанные/беззнаковые версии для всех модификаторов (int/unsigned int, size_t/ssize_t и т. д.), кроме ptrdiff_t.

На практике ничего страшного не происходит, так как неподписанные версии типов занимают столько же места, сколько и подписанные версии. Таким образом, правое количество байтов выталкивается из стека.

Так что ничего «плохого» не происходит, на самом деле выводит ожидаемое значение для всех протестированных вещей, кроме «INT_MIN» (при условии, что sizeof(int) == sizeof(ptrdiff_t).

printf("%tu %td\n", INT_MIN, INT_MIN);

отпечатки

2147483648 -2147483648

на 32-битной системе.

Есть ли мнение стандарта по этому поводу? Я полагаю, что ответ будет "неопределенное поведение". Но я решил спросить ;).


c c99
person Evan Teran    schedule 31.03.2009    source источник
comment
Имеет ли это какое-либо отношение к C++ (по крайней мере, до C++0x)? Будет ли printf() и т. д. изменены в С++ 0x, чтобы соответствовать C99? Я думаю, вам следует удалить тег C++.   -  person David Thornley    schedule 01.04.2009
comment
ptrdiff_t определен в cstddef в С++. printf, очевидно, существует и в С++. Я вообще не знаю о том, что С++ 0x меняет printf.   -  person Evan Teran    schedule 01.04.2009
comment
хм, кажется, что c++ может не иметь модификатора c99 't'. Справедливо.   -  person Evan Teran    schedule 01.04.2009


Ответы (1)


Здесь нечего смотреть. Код, который вы написали, является законным.

Несколько фактов почему:

  • все целочисленные типы со знаком имеют аналоги без знака с одинаковыми требованиями к размеру/выравниванию
  • ptrdiff_t по стандарту предписывается быть целочисленным типом со знаком. Следовательно, у него есть беззнаковый двойник. (На самом деле аналогичная логика применима и к size_t - ssize_t это не C, а POSIX)
  • спецификатор длины t должен работать с типами d, i, o, u, x, X
person jpalecek    schedule 31.03.2009
comment
каков допустимый беззнаковый эквивалент ptrdiff_t? - person user83255; 01.04.2009
comment
У него нет специального имени — вы можете только сказать, что если ptrdiff_t имеет значение long long, то его аналог без знака — unsigned long long и т. д. - person jpalecek; 01.04.2009
comment
Важный факт, который вы упустили, заключается в том, что в случаях, когда значение подходит как для знакового, так и для беззнакового вариантов целочисленного типа, оно имеет одинаковое представление, и стандарт явно разрешает передачу неправильного типа аргумента в этом случае (что возможно только во всяком случае, для функций без прототипов и функций с переменным числом переменных). Насколько я могу судить, UB будет передавать отрицательное значение ptrdiff_t, когда спецификатор формата ожидает тип без знака. - person R.. GitHub STOP HELPING ICE; 04.09.2011