У меня есть переменная типа size_t
, и я хочу распечатать его использование printf()
. Какой спецификатор формата я использую для печати его портативно?
В 32-разрядной машине, %u
кажется правильным. Я скомпилировал с g++ -g -W -Wall -Werror -ansi -pedantic
, и не было никакого предупреждения. Но когда я компилирую тот код в 64-разрядной машине, он производит предупреждение.
size_t x = <something>;
printf( "size = %u\n", x );
warning: format '%u' expects type 'unsigned int',
but argument 2 has type 'long unsigned int'
Предупреждение уходит, как ожидалось, если я изменяю это на %lu
.
Вопрос, как я могу написать код, так, чтобы он скомпилировал предупреждение свободного и на 32-и на машины на 64-биты?
Править: Как обходное решение, я предполагаю, что один ответ мог бы быть должен "бросить" переменную в целое число, которое является достаточно большим, сказать unsigned long
, и использование печати %lu
. Это работало бы в обоих случаях. Я смотрю, если существует какая-либо другая идея.
Используйте модификатор z
:
size_t x = ...;
ssize_t y = ...;
printf("%zu\n", x); // prints as unsigned decimal
printf("%zx\n", x); // prints as hex
printf("%zd\n", y); // prints as signed decimal
Для C89 используйте % lu
и приведите значение к unsigned long
:
size_t foo;
...
printf("foo = %lu\n", (unsigned long) foo);
Для C99 и позже используйте % zu
:
size_t foo;
...
printf("foo = %zu\n", foo);
std::size_t s = 1024;
std::cout << s; // or any other kind of stream like stringstream!
C99 определяет "% zd" и т. Д. для этого. (спасибо комментаторам) В C ++ нет переносимого спецификатора формата для этого - вы могли бы использовать % p
, что слово woulkd в этих двух сценариях, но не переносимый вариант либо, и дает значение в шестнадцатеричном формате.
В качестве альтернативы можно использовать потоковую передачу (например, stringstream) или безопасную замену printf, например Boost Format . Я понимаю, что этот совет имеет ограниченное применение (и требует C ++). (Мы использовали аналогичный подход, подходящий для наших нужд, при реализации поддержки юникода.)
Основная проблема для C состоит в том, что printf с многоточием небезопасен по замыслу - он должен определять размер дополнительного аргумента из известных аргументов, так что это не может быть исправлено, чтобы поддерживать "все, что у вас есть". Так что, если ваш компилятор не реализует некоторые проприетарные расширения, вам не повезло.
Похоже, это зависит от того, какой компилятор вы используете (blech):
% zu
(или % zx
, или % zd
, но отображается как подписанный и т. Д.) % Iu
(или % Ix
, или % Id
, но снова это подписано и т. д.) - но с cl v19 (в Visual Studio 2015) Microsoft поддерживает % zu
(см. этот ответ на этот комментарий ) ... и, конечно, если вы используете C ++, вы можете использовать cout
вместо , предложенного AraK .
Тем, кто говорит об этом на C ++, который не обязательно поддерживает расширения C99, я настоятельно рекомендую boost :: format. Это делает спорным вопрос о размере типа size_t:
std::cout << boost::format("Sizeof(Var) is %d\n") % sizeof(Var);
Поскольку вам не нужны спецификаторы размера в boost :: format, вы можете просто беспокоиться о том, как вы хотите отображать значение.
Будет ли он предупреждать вас, если вы передадите 32-битное целое число без знака в формат% lu? Это должно быть нормально, поскольку преобразование четко определено и не теряет никакой информации.
Я слышал, что некоторые платформы определяют макросы в
, которые можно вставить в литерал строки формата, но я не вижу этого заголовка в моем компиляторе Windows C ++, что подразумевает его не может быть кроссплатформенным.