спецификаторы формата 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

Большое спасибо за любой совет,

ant2009
источник
2
C89 не поддерживает uint32_tот <stdint.h>или <inttypes.h>; если вы хотите использовать эти типы, вам следует перейти на C89. В качестве расширения вполне вероятно, что GCC действительно позволяет их использовать, но C89 не имел такой поддержки.
Джонатан Леффлер,
10
И официальный модификатор формата C99 для size_t'z', как в "%zu".
Джонатан Леффлер
1
stackoverflow.com/questions/1401526/…
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
Я считаю, что ответ @kenny лучше всего подходит uint32_t, но его не хватает size_t. Ответ @ u0b34a0f6ae включает оба.
jww
Второе упоминание C89 в 1 - й комментарий Джонатана Леффлера должен быть C99
бут

Ответы:

28

Похоже, вы ожидаете size_tтого же unsigned long(возможно, 64 бита), хотя на самом деле unsigned int(32 бита). Попробуйте использовать %zuв обоих случаях.

Хотя я не совсем уверен.

Зубчатое колесо
источник
1
Никаких предупреждений при компиляции. Однако, запустив splint, я получаю следующее: 1) printf (% u) ожидает, что unsigned int получит uint32_t: i 2) printf (% u) ожидает, что unsigned int получит size_t: k
ant2009 02
Значит, шина - это просто педантизм. Вероятно, это происходит от названий типов в исходном коде и не понимает, что они эквивалентны. Интересно, что он будет делать с ответом @KennyTM ... Он определенно должен быть более портативным.
Cogwheel
3
шина на самом деле делает правильные вещи. Тот int32_tфакт, что он находится intна вашем компиляторе / платформе, не означает, что его может не быть longна другом. То же самое для size_t. Это на самом деле происходит из его пути и делать больше работы , чтобы обнаружить эту ошибку , так как портативность легкий, естественный контроль будет просто чтить ЬурейуЮ как компилятор делает.
R .. GitHub НЕ ПОМОГАЕТ ICE
4
-1, извините, не портативный. Все, что нужно, - это согласование спецификаторов формата и типов, и вы всегда можете выполнить приведение, чтобы это стало правдой. long составляет не менее 32 бита, поэтому %luвместе с (unsigned long)kвсегда правильно. size_tсложнее, поэтому он %zuбыл добавлен в C99. Если вы не можете его использовать, относитесь к нему так же, как k( longэто самый большой тип в C89, size_tвряд ли он будет больше).
u0b34a0f6ae 08
140

Пытаться

#include <inttypes.h>
...

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

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

Kennytm
источник
3
@robUK: Хех. Предлагаю вам зарегистрировать ошибку для шины.
kennytm 02
8
Это правильный ответ. Хотя моя личная рекомендация - просто забросить, например printf( "%lu", (unsigned long )i ). В противном случае позже вы получите кучу предупреждений по всему коду из-за изменения типа.
Dummy00001 02
1
Это правильный ответ. Я согласен с KennyTM о регистрации ошибки для шины. Кстати, "% zu" - правильный формат для size_t. Вам не нужны никакие макросы PRI * для печати size_t.
R .. GitHub ПРЕКРАТИТЕ ПОМОЩЬ ICE
1
Если я правильно помню,% zu - это C99, а в вопросе он написал «C89».
alcor
8
@alcor да, он действительно поставил C89 (очевидно, флаг компилятора gcc, который он использует), но он использует, uint32_tтак что на самом деле это код C99, и он должен быть скомпилирован как таковой.
Colin D Bennett
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будет эквивалентно чтению слишком большого или слишком малого объема памяти из массива. Пока вы используете явное приведение типов для сопоставления типов, это переносимо.

u0b34a0f6ae
источник
17

Если вы не хотите использовать макросы PRI *, другой подход к печати ЛЮБОГО целочисленного типа - приведение к intmax_tили uintmax_tи использование "%jd"или %ju, соответственно. Это особенно полезно для типов POSIX (или других ОС), для которых, например, не определены макросы PRI * off_t.

R .. GitHub НЕ ПОМОГАЕТ ICE
источник