специфікатори формату printf для uint32_t та size_t


101

У мене є таке

size_t   i = 0;
uint32_t k = 0;

printf("i [ %lu ] k [ %u ]\n", i, k);

Я отримую таке попередження при компілюванні:

format ‘%lu expects type long unsigned int’, but argument has type uint32_t

Коли я запустив це за допомогою шини, я отримав наступне:

Format argument 1 to printf (%u) expects unsigned int gets size_t: k

Дякую за будь-яку пораду,


2
C89 не підтримує uint32_tвід <stdint.h>або <inttypes.h>; якщо ви хочете використовувати ці типи, вам слід оновити до C89. Як розширення, ймовірно, що GCC дозволяє вам використовувати їх, але C89 не мав такої підтримки.
Джонатан Леффлер

10
А офіційний модифікатор формату C99 для size_t"z", як у "%zu".
Джонатан Леффлер


Я вважаю, що відповідь @ kenny найкраща uint32_t, але її немає size_t. @ u0b34a0f6ae відповідь включає і те, і інше.
jww

Друга згадка про C89 у 1-му коментарі Джонатана Леффлера має бути C99
bph

Відповіді:


28

Звучить так, що ви розраховуєте size_tбути таким же, як unsigned long(можливо, 64 біти), коли це насправді unsigned int(32 біта). Спробуйте використовувати %zuв обох випадках.

Я не зовсім впевнений.


1
Ніяких попереджень при компілюванні. Однак, запускаючи шину, я отримую наступне: 1) printf (% u) очікує, що без підписання int стає uint32_t: i 2) printf (% u) очікує, що без підпису int отримує size_t: k
ant2009

Тоді звуки, як шина, просто педантичні. Це, ймовірно, вимикає назви типів у вихідному коді і не розуміє, що вони еквівалентні Цікаво, що це зробить з відповіддю @ KennyTM ... Це, звичайно, повинно бути більш портативним.
Cogwheel

3
шина насправді робить правильно. Просто те, що int32_tтрапляється intна вашому компіляторі / платформі, не означає, що воно може бути не longна іншому Те саме для size_t. Це насправді виходить зі свого шляху і робить більше роботи, щоб виявити цю помилку переносимості, оскільки легка, природна перевірка була б просто шанувати typedef, як це робить компілятор.
R .. GitHub СТОП ДОПОМОГАТИ ЛІС

4
-1, вибачте, що це не портативно. Все, що потрібно, - це те, що специфікатори формату та типи узгоджуються, і ви завжди можете це зробити, щоб зробити це правдою. Довгий принаймні 32 біт, тому %luразом з ним (unsigned long)kзавжди правильно. size_tє складнішим, тому %zuдодано в C99. Якщо ви не можете використовувати це, то поводьтеся з ним так само k( longце найбільший тип C89, size_tнавряд чи буде більшим).
u0b34a0f6ae

139

Спробуйте

#include <inttypes.h>
...

printf("i [ %zu ] k [ %"PRIu32" ]\n", i, k);

Представлення zявляє собою ціле число довжини, таке ж, як size_tі PRIu32макрос, визначений у заголовку C99inttypes.h , являє собою непідписане 32-бітове ціле число.


3
@robUK: Хе. Я пропоную вам подати помилку для шини.
kennytm

8
Це правильна відповідь. Хоча моя особиста рекомендація полягає в тому, щоб просто подати заявку, наприклад printf( "%lu", (unsigned long )i ). Інакше пізніше виникла куча попереджень у всьому коді через зміну типу.
Dummy00001

1
Це правильна відповідь. Я погоджуюся з KennyTM щодо подання помилки на шину. До речі, "% zu" - це правильний формат для size_t. Для друку size_t вам не потрібен жоден із макросів PRI *.
R .. GitHub СТОП ДОПОМОГАТИ ВІД

1
Якщо я правильно пам'ятаю,% zu - це C99, і в запитанні він написав "C89".
alcor

8
@alcor так, він поставив C89 (мабуть, прапор компілятора gcc, який він використовує), але він використовує uint32_tтак, що це фактично код C99, і його слід скласти як такий.
Колін Д Беннетт

28

Все, що потрібно, - це те, що специфікатори формату та типи узгоджуються, і ви завжди можете це зробити, щоб зробити це правдою. longпринаймні 32 біта, тому %luразом із (unsigned long)kзавжди правильним:

uint32_t k;
printf("%lu\n", (unsigned long)k);

size_tє складнішим, тому %zuдодано в C99. Якщо ви не можете використовувати це, то поводьтеся з ним так само k( longце найбільший тип C89, size_tнавряд чи буде більшим).

size_t sz;
printf("%zu\n", sz);  /* C99 version */
printf("%lu\n", (unsigned long)sz);  /* common C89 version */

Якщо ви не знайдете специфікаторів формату правильним для типу, який ви передаєте, тоді printfбуде виконано еквівалент читання занадто багато або занадто мало пам'яті з масиву. Поки ви використовуєте явні касти для відповідності типам, це портативно.


17

Якщо ви не хочете використовувати макроси PRI *, інший підхід для друку будь-якого цілого типу - це передавання intmax_tабо uintmax_tвикористання відповідно "%jd"або %ju. Це особливо корисно для POSIX (або інших ОС), наприклад, для яких не визначено макросів PRI * off_t.

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