У меня есть переменная типа 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
. Это будет работать в обоих случаях. Я смотрю, есть ли другая идея.
unsigned long
- лучший вариант, если ваша реализация libc не поддерживаетz
модификатор; стандарт C99 рекомендуетsize_t
не иметь целочисленного ранга преобразования выше, чемlong
, поэтому вы достаточно безопасныОтветы:
Используйте
z
модификатор:источник
printf()
модификаторов длины черновика C ++ 0x от 2009-11-09 (таблица 84 на стр. 672)-pedantic
, вам нужно либо получить компилятор, поддерживающий черновой вариант C ++ 1x (крайне маловероятно), либо вам нужно переместить свой код в файл, скомпилированный как C99. В противном случае, ваш единственный вариант - привести ваши переменныеunsigned long long
и использовать%llu
их как максимально переносимые.Похоже, это зависит от того, какой компилятор вы используете (blech):
%zu
(или%zx
, или,%zd
но это показывает, как будто оно было подписано, и т. д.)%Iu
(или%Ix
, или,%Id
но опять же, подписано и т. Д.) - но по состоянию на cl v19 (в Visual Studio 2015) Microsoft поддерживает%zu
(см. Этот ответ на этот комментарий )... и, конечно, если вы используете C ++, вы можете использовать
cout
вместо этого, как предложено AraK .источник
z
также поддерживается newlib (то есть cygwin)%zd
неверно дляsize_t
; это верно для подписанного типа, соответствующегоsize_t
, ноsize_t
сам по себе является неподписанным типом.%zu
(и%zx
в случае, если они хотят hex). Достаточно верно, что,%zu
вероятно, должен был быть первым в списке. Исправлена.%zd
должен быть в списке вообще. Я не могу думать ни о какой причине, чтобы использовать%zd
вместо того,%zu
чтобы напечататьsize_t
значение. Это даже не верно (имеет неопределенное поведение), если значение превышаетSIZE_MAX / 2
. (Для полноты вы можете упомянуть%zo
о восьмеричном.)ssize_t
это был тип со знаком, соответствующийsize_t
, поэтому он не гарантированно совпадает"%zd"
. (Это, вероятно , на большинстве реализаций.) Pubs.opengroup.org/onlinepubs/9699919799/basedefs/…Для C89 используйте
%lu
и приведите значение кunsigned long
:Для C99 и более поздних версий используйте
%zu
:источник
unsigned long long
?uint64_t
а затем использоватьPRIu64
макрос из inttypes.h, который содержит спецификатор формата.Расширение на ответ Адама Розенфилда для Windows.
Я тестировал этот код на VS2013 Update 4 и VS2015 preview:
VS2015 генерирует двоичные выходы:
в то время как тот, созданный VS2013, говорит:
Примечание:
ssize_t
это расширение POSIX иSSIZE_T
аналогичное в типах данных Windows , поэтому я добавил<BaseTsd.h>
ссылку.Кроме того, за исключением следующих заголовков C99 / C11, все заголовки C99 доступны в предварительном просмотре VS2015:
Кроме того, C11
<uchar.h>
теперь включен в последний предварительный просмотр.Для получения дополнительной информации см. Этот старый и новый список для соответствия стандарту.
источник
Тем, кто говорит об этом в C ++, который не обязательно поддерживает расширения C99, я настоятельно рекомендую boost :: format. Это делает вопрос размера size_t спорным:
Поскольку вам не нужны указатели размера в boost :: format, вы можете просто беспокоиться о том, как вы хотите отобразить значение.
источник
%u
тогда.источник
printf
уточнения. Я предполагаю, что у них есть некоторые другие неустановленные ограничения, которые делают использованиеstd::cout
проблемы.printf
спецификатора ".источник
Как сказал АраК, интерфейс потоков c ++ всегда будет работать переносимо.
Если вы хотите использовать C stdio, для некоторых случаев «портативного» ответа на этот вопрос не существует. И это уродливо, поскольку, как вы уже видели, выбор неправильных флагов формата может привести к предупреждению компилятора или неверному выводу.
C99 пытался решить эту проблему с помощью таких форматов inttypes.h, как "%" PRIdMAX "\ n". Но, как и в случае с «% zu», не все поддерживают c99 (как MSVS до 2013 года). Есть файлы "msinttypes.h", которые разбираются с этим.
Если вы приведете к другому типу, в зависимости от флагов вы можете получить предупреждение компилятора об усечении или изменении знака. Если вы идете по этому маршруту, выберите больший соответствующий тип фиксированного размера. Один из unsigned long long и "% llu" или unsigned long "% lu" должен работать, но llu также может замедлить работу в 32-битном мире как чрезмерно большой. (Изменить - мой Mac выдает предупреждение в 64-битной версии, что% llu не соответствует size_t, хотя% lu,% llu и size_t имеют одинаковый размер. И% lu и% llu не совпадают по размеру на моем MSVS2012. вам может понадобиться привести + использовать формат, который соответствует.)
В этом отношении вы можете использовать фиксированные размеры, такие как int64_t. Но ждать! Теперь мы вернулись к c99 / c ++ 11, и старый MSVS снова дает сбой. Плюс у вас также есть приведения (например, map.size () не является фиксированным размером)!
Вы можете использовать сторонний заголовок или библиотеку, такую как boost. Если вы еще не используете его, возможно, вы не захотите раздувать свой проект таким образом. Если вы готовы добавить один только для этой проблемы, почему бы не использовать потоки C ++ или условную компиляцию?
Таким образом, вы знакомы с потоками c ++, условной компиляцией, сторонними фреймворками или чем-то вроде портативного устройства, которое работает на вас.
источник
Будет ли он предупреждать вас, если вы передадите 32-разрядное целое число без знака в формат% lu? Это должно быть хорошо, так как преобразование четко определено и не теряет никакой информации.
Я слышал, что некоторые платформы определяют макросы в
<inttypes.h>
том смысле, что вы можете вставить их в строковый литерал формата, но я не вижу этого заголовка в моем компиляторе Windows C ++, что подразумевает, что он не может быть кроссплатформенным.источник
%lu
, вы должны привестиsize_t
значение кunsigned long
. Не существует неявного преобразования (кроме рекламных) для аргументов вprintf
.C99 определяет "% zd" и т. Д. Для этого. (спасибо комментаторам) В C ++ нет переносимого спецификатора формата - вы можете использовать
%p
, какое слово woulkd в этих двух сценариях, но также не является переносимым выбором, и дает значение в шестнадцатеричном формате.В качестве альтернативы используйте потоковую передачу (например, stringstream) или безопасную замену printf, например Boost Format . Я понимаю, что этот совет имеет ограниченное использование (и требует C ++). (Мы использовали подобный подход, приспособленный для наших нужд при реализации поддержки юникода.)
Фундаментальная проблема для C состоит в том, что printf, использующий многоточие, небезопасен по своей конструкции - он должен определить размер дополнительного аргумента из известных аргументов, поэтому он не может быть исправлен для поддержки «что бы вы ни получили». Так что, если ваш компилятор не реализует некоторые проприетарные расширения, вам не повезло.
источник
z
размер modidfier является стандартным C, но некоторые Libc реализации застряла в 1990 году по различным причинам (например , Microsoft в основном заброшенные C в пользу C ++ и - совсем недавно - C #)%zd
это неправильно, это без знака, так и должно быть%zu
.На некоторых платформах и для некоторых типов доступны определенные спецификаторы преобразования printf, но иногда приходится прибегать к приведению к более крупным типам.
Я задокументировал эту сложную проблему здесь, с примером кода: http://www.pixelbeat.org/programming/gcc/int_types/ и периодически обновляю его информацией о новых платформах и типах.
источник
если вы хотите напечатать значение size_t в виде строки, вы можете сделать это:
результат:
номер: 2337200120702199116
Текст: Пойдем на рыбалку вместо того, чтобы сидеть на нашем но !!
Редактировать: перечитывая вопрос из-за отрицательных голосов, я заметил, что его проблема не в% llu или% I64d, а в типе size_t на разных машинах, смотрите этот вопрос https://stackoverflow.com/a/918909/1755797
http: // www. cplusplus.com/reference/cstdio/printf/
size_t - это unsigned int на 32-битной машине и unsigned long long int на 64-битной системе,
но% ll всегда ожидает unsigned long long int.
size_t различается по длине в разных операционных системах, в то время как% llu одинаково
источник