Как мне печатать такие типы, как off_t и size_t?

148

Я пытаюсь напечатать такие типы, как off_tи size_t. Каков правильный заполнитель для printf() этого портативного ?

Или есть совершенно другой способ печати этих переменных?

Георг Шолли
источник
2
@devin: Я считаю , что я обнаружил , что тип при использовании fopen, fseekи т.д. на Mac OS X. off_tиспользуется для смещения.
Георг Шолли

Ответы:

112

Вы можете использовать zдля size_t и tдля ptrdiff_t, как в

printf("%zu %td", size, ptrdiff);

Но моя справочная страница гласит, что в какой-то более старой библиотеке использовался символ, отличающийся от используемого, zи не одобряет его использование. Тем не менее, он стандартизирован (по стандарту C99). Для тех intmax_tи int8_tдругих stdint.hи так далее, вы можете использовать макросы, как сказал другой ответ:

printf("value: %" PRId32, some_int32_t);
printf("value: %" PRIu16, some_uint16_t);

Они перечислены на странице руководства inttypes.h.

Лично я бы просто привел значения к unsigned longили longкак другой ответ рекомендует. Если вы используете C99, то вы можете (и, конечно, должны) приводить к unsigned long longили long longиспользовать форматы %lluили %lldсоответственно.

Йоханнес Шауб - Литб
источник
2
На самом деле off_t - это длинная подпись в моей системе.
Георг Шолли
2
Я думаю, что страница руководства не рекомендует использовать Z (заглавные буквы), который использовался libc5. Кажется, это не препятствует z (строчные буквы).
Draemon
12
Использование %zdс size_tявляется неопределенным поведением из-за несоответствия подписи (C99 7.19.6.1 # 9). Должно быть %zu.
Дженс
7
Ну как распечатать off_t тогда?
JohnyTex
3
@Jens Я не понимаю, как %zdс помощью size_tполучить неопределенное поведение из этого абзаца или из любого другого. Фактически, определение %zв # 7 явно разрешает %dс size_tи соответствующий тип со знаком, а §6.2.5 # 9 явно позволяет использовать значения беззнаковых типов, где ожидается соответствующий тип со знаком, при условии, что значение является действительным неотрицательным значением подписанного типа.
Chortos-2
108

Для печати off_t:

printf("%jd\n", (intmax_t)x);

Для печати size_t:

printf("%zu\n", x);

Для печати ssize_t:

printf("%zd\n", x);

См. 7.19.6.1/7 в стандарте C99 или более удобную документацию POSIX по форматированию кодов:

http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html

Если ваша реализация не поддерживает эти коды форматирования (например, потому что вы на C89), то у вас есть небольшая проблема, так как в AFAIK нет целочисленных типов в C89, которые имеют коды форматирования и гарантированно будут такими же большими как эти типы. Так что вам нужно сделать что-то конкретное для реализации.

Например, если ваш компилятор имеет long longи ваша стандартная библиотека поддерживает %lld, вы можете с уверенностью ожидать, что он будет использоваться вместо intmax_t. Но если этого не произойдет, вам придется вернуться к этому long, что не получится в некоторых других реализациях, потому что он слишком мал.

Стив Джессоп
источник
3
Это лучший ответ, я бы забыл об использовании% zu для unsigned size_t. А приведение к intmax_t - отличное решение для любого off_t на любой платформе.
Питер Кордес,
2
POSIX не гарантирует, что он ssize_tимеет тот же размер size_t, что и действительно переносимый код, должен преобразовывать его в intmax_tи печатать так %jdже, как off_t.
nwellnhof
off_t может иметь размер long long и может быть переменной в зависимости от определений ... Visual Studio также предупреждает об этом "предупреждение C4477: '_snprintf_s': строка формата"% jd "требует аргумент типа '__int64', но аргумент variadic 1 имеет тип 'off_t' "... Истинно переносимым способом является printf ("% lld \ n ", (long long) x);
Эриккуртин
5

Для Microsoft ответ другой. VS2013 в значительной степени совместим с C99, но «префиксы длины [t] he hh, j, z и t не поддерживаются». Для size_t «то есть без знака __int32 на 32-битных платформах, без знака __int64 на 64-битных платформах» используйте префикс I (заглавные буквы) со спецификатором типа o, u, x или X. См. Спецификацию размера VS2013

Что касается off_t, он определяется как long в VC \ include \ sys \ types.h.

NoBrassRing
источник
Обратите внимание, если off_tвсегда long, это сделает его 32-битным (даже для 64-битной Windows используется 32-битная версия long).
sourcejedi
3

Какую версию C вы используете?

В C90 стандартной практикой является приведение к подписанному или неподписанному длинному, в зависимости от ситуации, и печати соответственно. Я видел% z для size_t, но Харбисон и Стил не упоминают об этом в printf (), и в любом случае это не поможет вам с ptrdiff_t или чем-то еще.

В C99 различные типы _t поставляются со своими собственными макросами printf, так что "Size is " FOO " bytes." я не знаю деталей, но это часть довольно большого числового формата включаемого файла.

Дэвид Торнли
источник
3

Вы захотите использовать макросы форматирования из inttypes.h.

Смотрите этот вопрос: Строка формата кроссплатформенного для переменных типа size_t?

Майкл Берр
источник
Если предположить, что off_t - это целое число со знаком, размером с указатель (я не знаю, каково точное определение), например ptrdiff_t, тогда вы будете использовать PRIdPTR или PRIiPTR.
Майкл Берр
11
off_tТипа больше , чем указатель на любой 32-битной системе , которая поддерживает большие файлы (что большинство 32-битные системы в эти дни).
Дитрих Эпп
1
@DietrichEpp: На самом деле, это еще хуже; многие 32-битные системы имеют как off_t, так и off64_t, и в зависимости от макроса функции off_t может фактически означать off64_t.
SamB
1

Рассматривая в man 3 printfLinux, OS X и OpenBSD все показывает поддержку %zдля size_tи %tдля ptrdiff_t(для C99), но ни один из них не упоминает off_t. Предложения в дикой природе обычно предлагают %uпреобразование для off_t, что, насколько я могу судить, является «достаточно правильным» (как одинаковым, так unsigned intи off_tразным для 64-битных и 32-битных систем).

DWC
источник
1
Моя система (OS X) имеет 32-разрядную unsigned intи 64-разрядную версию off_t. Таким образом, приведение может привести к потере данных.
Дитрих Эпп
-3

Я видел этот пост по крайней мере дважды, потому что принятый ответ трудно запомнить для меня (я редко использую zили jотмечаю флаги, и они, кажется, не зависят от платформы ).

В стандарте никогда точно не указывается точная длина данных size_t, поэтому я советую сначала проверить длину size_tна своей платформе, а затем выбрать один из них:

if sizeof(size_t) == 4 use PRIu32
if sizeof(size_t) == 8 use PRIu64

И я предлагаю использовать stdintтипы вместо необработанных типов данных для согласованности.

elinx
источник
1
Для C99 и C11 в стандарте прямо указано, что %zuможно использовать для печати size_tзначений. Определенно не следует прибегать к использованию спецификатора uint32_t/ uint64_tformat для печати a size_t, поскольку нет гарантии, что эти типы совместимы.
аутист
-4

Насколько я помню, единственный переносимый способ сделать это - привести результат к «unsigned long int» и использовать %lu.

printf("sizeof(int) = %lu", (unsigned long) sizeof(int));
Джеймс Керран
источник
1
Должно быть "% lu", так как модификатор длины должен быть до преобразования.
DWC
1
off_t, например, длинная подпись.
Георг Шолли
@ GeorgSchölly - Тогда вы натолкнулись на головоломку, потому long longчто не существует в стандарте C ++ и, следовательно, по своей сути не переносимы.
Джеймс Керран
-9

используйте "% zo" для off_t. (восьмеричное) или "% zu" для десятичного числа.

Шанкар
источник
Зачем вам смещение файла в восьмеричном?
пул