Как распечатать значение переменных uint32_t через функцию wprintf?

Общеизвестно, что для печати значений переменных, тип которых является одним из целочисленных типов с фиксированной шириной (например, uint32_t), вам необходимо включить заголовочный файл cinttypes (в C++) или inttypes.h (в C) и использовать макросы спецификаторов формата, такие как PRIu32. Но как сделать то же самое при использовании функции wprintf? В этом случае такой макрос должен раскрываться как строковый литерал с префиксом L.


person Constructor    schedule 29.04.2016    source источник
comment
На каком из C и C++ вы программируете? Пожалуйста, выберите не более одного.   -  person fuz    schedule 29.04.2016
comment
@FUZxxl Почему я должен выбрать только один?   -  person Constructor    schedule 29.04.2016
comment
В чем собственно проблема? Ваш код не компилируется? Отображает ли wprintf что-то другое, чем вы ожидаете?   -  person Jabberwocky    schedule 29.04.2016
comment
Потому что обычно ответ другой, но, возможно, не в этом случае. Кроме того, использование printf() не так распространено в программах c++, используйте <iostream>, и он со всем этим справляется.   -  person Iharob Al Asimi    schedule 29.04.2016
comment
@MichaelWalz Да, конечно. wprintf принимает только строку широких символов в качестве строки формата.   -  person Constructor    schedule 29.04.2016
comment
@iharob Думаю, в данном случае разницы нет. И да, printf не так уж часто используется в C++, но в некоторых случаях это может быть полезно.   -  person Constructor    schedule 29.04.2016
comment
@Constructor Я знаю, поэтому мне больше нравится c.   -  person Iharob Al Asimi    schedule 29.04.2016
comment
Можете ли вы опубликовать пример, который не компилируется? Я просто не вижу необходимости в расширенной версии PRIu32.   -  person cremno    schedule 29.04.2016
comment
@Constructor Вопрос о коде более чем на одном языке программирования слишком широк. Либо сузьте его до одного языка, либо смотрите, как ваш вопрос закрывается.   -  person fuz    schedule 29.04.2016
comment
@Constructor У меня недостаточно времени, чтобы применять правила ко всем вопросам, и иногда (но не здесь) комбинация тегов правильная. Тем не менее, я рекомендую вам придерживаться их. Вопросы должны быть об одном языке, за исключением случаев, когда они касаются взаимодействия между несколькими языками.   -  person fuz    schedule 29.04.2016


Ответы (4)


Будет ли это работать или нет, на самом деле зависит от того, какой стандарт C использует компилятор.

Из этой ссылки на строковый литерал

Можно конкатенировать только два узких или два широких строковых литерала. (до C99)

а также

Если один литерал не имеет префикса, результирующий строковый литерал имеет ширину/кодировку, указанные литералом с префиксом. Если два строковых литерала имеют разные префиксы кодирования, конкатенация определяется реализацией. (начиная с C99)

[Выделено мое]

Поэтому, если вы используете старый компилятор или тот, который не поддерживает стандарт C99 (или более позднюю версию), это невозможно. Кроме того, целочисленные типы с фиксированной шириной были стандартизированы в C99, поэтому макросы на самом деле не существуют для таких старых компиляторов, что делает вопрос спорным.

Для более современных компиляторов, поддерживающих C99 и более поздние версии, это не проблема, поскольку конкатенация строковых литералов будет работать, и компилятор превратит строку без префикса в строку широких символов, поэтому, например,

wprintf(L"Value = %" PRIu32 "\n", uint32_t_value);

будет работать нормально.


Если у вас есть компилятор до C99, но все еще есть макросы и целые типы с фиксированной шириной, вы можете использовать макросы, подобные функциям, для добавления префикса L перед строковыми литералами. Что-то типа

#define LL(s) L ## s
#define L(s) LL(s)

...

wprintf(L"Value = %" L(PRIu32) L"\n", uint32_t_value);
person Some programmer dude    schedule 29.04.2016
comment
Спасибо за ваш ответ. Вы правы, я использую старый компилятор и с ним проблема. - person Constructor; 29.04.2016
comment
Есть ли обходной путь для C89-совместимых компиляторов? - person Constructor; 29.04.2016
comment
@Constructor Должно быть возможно использование некоторых макросов, подобных функциям. Обновил мой ответ. - person Some programmer dude; 29.04.2016
comment
@Конструктор: #undef PRIu32, а затем #define PRIu32 L"u". Тогда wprintf(L"Value = %" PRIu32 "\n", uint32_t_value); должен работать со старыми компиляторами, по крайней мере, с моей старой Visual Studio 6. - person Jabberwocky; 29.04.2016
comment
@MichaelWalz Знаете ли вы назначение таких макросов, как PRIu32? - person Constructor; 29.04.2016
comment
@JoachimPileborg Я, конечно, знаю его цель, но я думаю, что Майкл Уолз этого не знает. - person Constructor; 29.04.2016
comment
@Constructor, конечно, я знаю его цель, но я не стал отвечать, потому что Иоахим Пилеборг был быстрее. - person Jabberwocky; 29.04.2016

Не уверен, в чем проблема, но здесь (VS 2015) оба

wprintf(L"AA %" PRIu32 L" BB", 123);

а также

printf("AA %" PRIu32 " BB", 123);

скомпилировать правильно и дать следующий вывод:

AA 123 BB
person Jabberwocky    schedule 29.04.2016
comment
Код, скомпилированный одним компилятором, необязательно соответствует стандартам. - person Constructor; 29.04.2016
comment
@Constructor Я никогда этого не утверждал. - person Jabberwocky; 29.04.2016

Даже если ваш компилятор не поддерживает конкатенацию литералов с разными префиксами, вы всегда можете расширить узкий:

#define WIDE(X) WIDE2(X)
#define WIDE2(X) L##X

wprintf(L"%" WIDE(PRIu32), foo);

Демо

person n. 1.8e9-where's-my-share m.    schedule 29.04.2016

(Более слабая) альтернатива использованию макросов из <inttypes.h> заключается в преобразовании/приведении типа фиксированной ширины к эквивалентному или большему стандартному типу.

wprintf(L"%lu\n", 0ul + some_uint32_t_value);
// or 
wprintf(L"%lu\n", (unsigned long) some_uint32_t_value);
person chux - Reinstate Monica    schedule 29.04.2016