Як слід друкувати такі типи, як 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
Я думаю, що сторінка man перешкоджає використанню Z (великі регістри), який використовував libc5. Схоже, це не відлякує z (малі літери).
Draemon

12
Використання %zdз a 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 явно дозволяє використовувати значення неподписаних типів, де очікується відповідний підписаний тип, якщо значення є дійсним негативним значенням підписаного типу.
Чортос-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 для непідписаного size_t. І передача до intmax_t - це чудове рішення для того, що б не було на будь-якій платформі.
Пітер Кордес

2
POSIX не гарантує, що ssize_tмає такий же розмір, як size_t, тому справді портативний код повинен конвертувати його intmax_tта друкувати %jdтак само off_t.
nwellnhof

off_t може бути довгим розміром і може бути змінним залежно від визначених ... Visual Studio попереджає про це також "попередження C4477: '_snprintf_s': рядок формату '% jd' вимагає аргументу типу '__int64', але варіативний аргумент 1 має тип 'off_t' "... Істинно портативним способом є printf ("% lld \ n ", (long long) x);
ericcurtin

5

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

Що стосується off_t, то він визначений, поки у VC \ include \ sys \ types.h.


Зверніть увагу, якщо 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 є підписаним, вказівником розміру int (я не знаю, яке точне визначення), наприклад, ptrdiff_t, тоді ви використовуєте PRIdPTR або PRIiPTR.
Майкл Берр

11
Цей off_tтип більший, ніж покажчик у будь-якій 32-бітній системі, яка підтримує великі файли (що є більшістю 32-бітних систем у ці дні).
Дітріх Епп

1
@DietrichEpp: Насправді, це гірше; у багатьох 32-бітних системах є і off_t, і off64_t, і залежно від функції макросів off_t може насправді означати off64_t.
СамБ

1

Дивлячись man 3 printfна Linux, OS X і OpenBSD, всі демонструють підтримку %zдля size_tі %tдля ptrdiff_t(для C99), але жоден з них не згадує off_t. Пропозиції в природі зазвичай пропонують %uконверсію для off_t, яка є "достатньо правильною", наскільки я можу сказати (як unsigned intі off_tвідрізняються однаково між 64-бітною та 32-бітовою системами).


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типи замість необроблених типів даних для узгодженості.


1
Для C99 і C11 стандарт прямо вказує, що %zuможна використовувати для друку size_tзначень. Однозначно не слід вдаватися до використання специфікатора uint32_t/ uint64_tформату для друку size_t, оскільки немає гарантії сумісності цих типів.
аутист

-4

Як я пам’ятаю, єдиний портативний спосіб це зробити - це передавати результат на «неподписаний довгий 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" для десяткової.


Чому ви хочете, щоб файл зміщений у восьмеричному?
poolie
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.