Почему новые строки опций формата printf() не были приняты как часть C99?

Исследуя, как сделать строки кросс-платформенного формата printf() в C (то есть, принимая во внимание количество битов, которое, как я ожидаю, должен иметь каждый целочисленный аргумент printf()), я наткнулся на этот раздел статьи Википедии о printf(). В статье обсуждаются нестандартные параметры, которые могут быть переданы в строки формата printf(), такие как (похоже, расширение Microsoft):

printf("%I32d\n", my32bitInt);

Далее говорится, что:

ISO C99 включает заголовочный файл inttypes.h, который содержит ряд макросов для использования в независимом от платформы кодировании printf.

... а затем перечисляет набор макросов, которые можно найти в указанном заголовке. Глядя на заголовочный файл, чтобы использовать их, мне пришлось бы написать:

 printf("%"PRId32"\n", my32bitInt);

Мой вопрос: я что-то упустил? Это действительно стандартный способ C99? Если да, то почему? (Хотя я не удивлен, что никогда не видел код, который использует строки формата таким образом, поскольку он кажется таким громоздким...)


person mpontillo    schedule 26.07.2009    source источник


Ответы (5)


Обоснование C, по-видимому, подразумевает, что ‹inttypes.h› стандартизирует существующую практику:

‹inttypes.h› был создан на основе одноименного заголовка, найденного в нескольких существующих 64-разрядных системах.

но остальная часть текста не пишет об этих макросах, и я не помню, чтобы они существовали в то время.

Далее следует только предположение, основанное на опыте работы комитетов по стандартизации.

Одним из преимуществ макросов C99 по сравнению со стандартизированным дополнительным спецификатором формата для printf (обратите внимание, что C99 также добавил некоторые из них) является то, что предоставление <inttypes.h> и <stdint.h>, когда у вас уже есть реализация, поддерживающая требуемые функции конкретным способом реализации, — это просто запись двух файлов с адекватным typedef и макросы. Это снижает стоимость приведения существующей реализации в соответствие, снижает риск поломки существующих программ, использующих особенности существующей специфики реализации (стандартный способ не мешает) и облегчает портирование совместимых программ в реализации, у которых их нет. заголовки (они могут быть предоставлены программой). Кроме того, если конкретные способы реализации уже различались в то время, это не дает преимущества одной реализации над другой.

person AProgrammer    schedule 26.07.2009
comment
Один недостаток: вызов C из сборки. - person Ciro Santilli 新疆再教育营六四事件ۍ 24.10.2015

Правильно, именно так стандарт C99 говорит, что вы должны их использовать. Если вам нужен по-настоящему переносимый код, который на 100% соответствует букве стандартов, вы всегда должны печатать int, используя "%d", и int32_t, используя "%"PRId32.

Однако большинство людей не будут беспокоиться, так как очень мало случаев, когда отказ от этого будет иметь значение. Если вы не портируете свой код на Win16 или DOS, вы можете предположить, что это sizeof(int32_t) <= sizeof(int), поэтому случайно напечатать int32_t как int не опасно. Точно так же long long в значительной степени универсально 64-битный (хотя это не гарантируется), поэтому печать int64_t как long long (например, со спецификатором %llx) также безопасна.

Типы int_fast32_t, int_least32_t и другие практически не используются, поэтому вы можете себе представить, что соответствующие им спецификаторы формата используются еще реже.

person Adam Rosenfield    schedule 26.07.2009
comment
Мой вопрос: я что-то упустил? Это действительно стандартный способ C99? Если да, то почему? - person John Kugelman; 26.07.2009
comment
Хотя я действительно хотел бы знать, почему часть, я понимаю, что это несколько риторический вопрос. Я сомневаюсь, что кто-нибудь узнает, если только они не присутствовали на обсуждении в организациях по стандартизации, когда говорили о C99. Я представляю группу инженеров, обсуждающих преимущества необходимости внесения изменений в функцию printf(), когда у них уже есть строки формата для печати чего угодно. Вероятно, они просто решили сделать это #define и покончить с этим. Поэтому, если у кого-то еще нет глубокого понимания, я, скорее всего, приму этот ответ; это отвечает на большую часть моего вопроса. - person mpontillo; 26.07.2009
comment
Может быть, я пишу слишком много встроенного кода, но я большой поклонник использования макросов PRIx## в своих строках printf. Я всегда предполагаю, что int составляет 16 бит или больше. Как только вы сделали это некоторое время, вы привыкнете к этому. - person tomlogic; 06.04.2011
comment
Встроенное ПО в 2013 году постоянно использовало C, где sizeof(int) == 1 или 2. Этот код также нуждается в переносимости. - person chux - Reinstate Monica; 28.05.2013

Вы всегда можете выполнить приведение вверх и использовать %jd, который является спецификатором формата intmax_t.

printf("%jd\n", (intmax_t)(-2));

Я использовал intmax_t, чтобы показать, что можно использовать любой intXX_t, но простое приведение к long намного лучше для случая int32_t, а затем использовать %ld.

person u0b34a0f6ae    schedule 05.11.2011
comment
+1 за интересную идею, но я не уверен, что мне нравится идея потенциального преобразования 32-битного целого числа в 64-битное + значение во встроенной системе ... просто как-то неправильно. ;-) - person mpontillo; 07.11.2011
comment
когда вы используете printf, трата 4 байтов для временного хранения (если вообще) является наименьшей из ваших проблем с производительностью! ;) - person lambdapower; 17.05.2013

Я могу только догадываться, почему. Мне нравится ответ AProgrammer выше, но один аспект упускается из виду: что вы собираетесь добавить в printf в качестве модификатора формата? Уже есть два разных способа использования чисел в строке формата printf (ширина и точность). Было бы здорово добавить число третьего типа, чтобы сказать, сколько битов точности в аргументе, но куда вы собираетесь его поместить, чтобы не сбить людей с толку? К сожалению, одним из недостатков C является то, что printf не был разработан с учетом возможности расширения.

Макросы ужасны, но когда вам нужно написать код, переносимый на 32-битные и 64-битные платформы, они просто находка. Определенно спас мой бекон.

Я думаю, что ответ на ваш вопрос почему либо

  • Никто не мог придумать лучшего способа сделать это, или
  • Комитет по стандартам не мог договориться ни о чем, что, по их мнению, было явно лучше.
person Norman Ramsey    schedule 26.07.2009
comment
Хороший вопрос, но Microsoft добавила способ сделать это с помощью модификатора формата (что некрасиво, но работает). Одним из способов могло бы быть разъединение текущего мышления d = int, u = unsigned int и переназначение спецификаторов типа таким образом, чтобы d = int32_t, u = uint32_t. Это могло бы быть менее разрушительным для C, чем маршрут Java. (укажите разрядность каждого типа явно - что, возможно, они должны были сделать изначально...) Но это все равно потребовало бы изменений в реализациях printf(). Я думаю, что они просто выбрали легкий путь. - person mpontillo; 27.07.2009
comment
@Mike: у вас есть указатель на путь Microsoft? Я ненавижу макросы. И у меня уже есть большая часть реализации printf. - person Norman Ramsey; 27.07.2009
comment
Это было упомянуто в статье Википедии, на которую я дал ссылку, но здесь это прямо из источника: msdn.microsoft.com/en-us/library/tcxf1dw6.aspx - person mpontillo; 27.07.2009
comment
ИМХО, ANSI должен (и C все еще должен) разрешать спецификатору ... указывать приведения типов для различных типов аргументов. Если реализация библиотеки printf указывает в stdio.h, что все аргументы с плавающей запятой должны быть повышены до long double, все целочисленные аргументы должны быть повышены до int64_t или uint64_t и все указатели до void*, вызов может быть менее эффективным, чем в обычных правилах, но его поведение будет быть независимым от типа int [за исключением случаев, когда int больше 64 бит]. Если бы C89 сделал это, математика с плавающей запятой, возможно, не стала бы настолько деградировавшей с тех пор. - person supercat; 24.06.2015

Другая возможность: обратная совместимость. Если вы добавите больше спецификаторов формата в printf или дополнительные параметры, возможно, что спецификатор в каком-то коде до C99 будет интерпретировать строку формата по-другому.

С изменением C99 вы не меняете функциональность printf.

person tomlogic    schedule 06.04.2011