Как можно напечатать переменную size_t с помощью семейства printf? - PullRequest
339 голосов
/ 26 марта 2010

У меня есть переменная типа 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. Это будет работать в обоих случаях. Я смотрю, есть ли другая идея.

Ответы [ 12 ]

419 голосов
/ 26 марта 2010

Используйте модификатор 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
80 голосов
/ 26 марта 2010

Похоже, это зависит от того, какой компилятор вы используете (blech):

... и, конечно, если вы используете C ++, вы можете использовать cout вместо , предложенного AraK .

57 голосов
/ 26 марта 2010

Для C89 используйте %lu и приведите значение к unsigned long:

size_t foo;
...
printf("foo = %lu\n", (unsigned long) foo);

Для C99 и более поздних версий используйте %zu:

size_t foo;
...
printf("foo = %zu\n", foo);
9 голосов
/ 04 января 2015

Расширение на ответ Адама Розенфилда для Windows.

Я тестировал этот код на VS2013 Update 4 и VS2015 Предварительный просмотр:

// test.c

#include <stdio.h>
#include <BaseTsd.h> // see the note below

int main()
{
    size_t x = 1;
    SSIZE_T y = 2;
    printf("%zu\n", x);  // prints as unsigned decimal
    printf("%zx\n", x);  // prints as hex
    printf("%zd\n", y);  // prints as signed decimal
    return 0;
}

VS2015 генерирует двоичные выходы:

1
1
2

в то время как генерируемый VS2013 говорит:

ца
гх
зд

Примечание: ssize_t - это расширение POSIX, а SSIZE_T аналогично типам данных Windows , поэтому я добавил <BaseTsd.h> ссылку.

Кроме того, за исключением следующих заголовков C99 / C11, все заголовки C99 доступны в предварительном просмотре VS2015:

C11 - <stdalign.h>
C11 - <stdatomic.h>
C11 - <stdnoreturn.h>
C99 - <tgmath.h>
C11 - <threads.h>

Кроме того, C11's <uchar.h> теперь включен в последний предварительный просмотр.

Подробнее см. В этом старом и новом списке для стандартного соответствия.

5 голосов
/ 26 марта 2010

Для тех, кто говорит об этом в C ++, который не обязательно поддерживает расширения C99, я настоятельно рекомендую boost :: format. Это делает вопрос размера size_t спорным:

std::cout << boost::format("Sizeof(Var) is %d\n") % sizeof(Var);

Поскольку вам не нужны спецификаторы размера в boost :: format, вы можете просто беспокоиться о том, как вы хотите отобразить значение.

5 голосов
/ 26 марта 2010
std::size_t s = 1024;
std::cout << s; // or any other kind of stream like stringstream!
5 голосов
/ 26 марта 2010
printf("size = %zu\n", sizeof(thing) );
2 голосов
/ 27 февраля 2017

Как сказал АраК, интерфейс потоков c ++ всегда будет работать переносимо.

std :: size_t s = 1024;std :: cout << s;// или любой другой вид потока, например, stringstream!</p>

Если вы хотите использовать C stdio, для некоторых случаев «portable» не существует переносимого ответа на этот вопрос.И это уродливо, потому что, как вы уже видели, выбор неправильных флагов формата может привести к предупреждению компилятора или неверному выводу.

C99 пытался решить эту проблему с помощью форматов inttypes.h, таких как "%" PRIdMAX "\п».Но, как и в случае с «% 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 ++, условной компиляцией, сторонними фреймворками или чем-то вроде портативного устройства, которое работает на вас.

0 голосов
/ 08 марта 2017

если вы хотите напечатать значение size_t в виде строки, вы можете сделать это:

char text[] = "Lets go fishing in stead of sitting on our but !!";
size_t line = 2337200120702199116;

/* on windows I64x or I64d others %lld or %llx if it works %zd or %zx */
printf("number: %I64d\n",*(size_t*)&text);
printf("text: %s\n",*(char(*)[])&line);

результат:

номер: 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 одинаково

0 голосов
/ 23 июля 2013

На некоторых платформах и для некоторых типов доступны определенные спецификаторы преобразования printf, но иногда приходится прибегать к приведению к более крупным типам.

Я задокументировал эту хитрую проблему здесь, с примером кода: http://www.pixelbeat.org/programming/gcc/int_types/ и периодически обновляйте его информацией о новых платформах и типах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...