Независимые от платформы спецификаторы формата size_t в c?

86

Я хочу распечатать переменную типа size_tC, но похоже, что size_tона привязана к разным типам переменных на разных архитектурах. Например, на одной машине (64-битной) следующий код не выдает никаких предупреждений:

size_t size = 1;
printf("the size is %ld", size);

но на моей другой машине (32-разрядной) приведенный выше код выдает следующее предупреждающее сообщение:

предупреждение: формат '% ld' ожидает тип 'long int *', но аргумент 3 имеет тип 'size_t *'

Я подозреваю, что это связано с разницей в размере указателя, так что на моей 64-битной машине size_tэто псевдоним long int( "%ld"), тогда как на моей 32-битной машине size_tпсевдоним другого типа.

Есть ли спецификатор формата специально для size_t?

Итан Хейлман
источник
Ваше предупреждающее сообщение не соответствует коду. В предупреждении упоминаются указатели, в вашем коде их нет. Вы &куда-то убирали ?
Йенс
Указатели? Нет, я не получаю никаких предупреждений об указателях, фактически, в зависимости от того, на какой машине я запускаю этот код, иногда я не получаю никаких предупреждений вообще. Попробуйте следующий тестовый код: #include <stdio.h> int main () {size_t size = 1; printf ("размер% ld", размер); возврат 0; }
Итан Хейлман
1
@EthanHeilman Он имеет в виду тот факт, что в ваших предупреждениях говорится, warning: format '%ld' expects type 'long int *', but argument 3 has type 'size_t *'когда, вероятно, следует говорить warning: format '%ld' expects type 'long int', but argument 3 has type 'size_t'. Вы, возможно, использовали scanf()вместо этого, когда получили эти предупреждения?
RastaJedi

Ответы:

123

Да: используйте zмодификатор длины:

size_t size = sizeof(char);
printf("the size is %zu\n", size);  // decimal size_t ("u" for unsigned)
printf("the size is %zx\n", size);  // hex size_t

Другие доступные модификаторы длины: hh(для char), h(для short), l(для long), ll(для long long), j(для intmax_t), t(для ptrdiff_t) и L(для long double). См. §7.19.6.1 (7) стандарта C99.

Адам Розенфилд
источник
в чем разница между zd и zu? Я понимаю, что zd является десятичным, но подписан ли он, если да, то как это влияет на подписание zd.
Итан Хейлман,
1
Это разница между a size_tи an ssize_t; последний используется редко.
Адам Розенфилд
26
Верно, в этом случае вы должны использовать %zu, потому что аргумент беззнаковый.
caf,
Другие доступные параметры описаны на странице руководства printf: linux.die.net/man/3/printf
INS
9
@detly: Нет, zмодификатор длины не является частью C89 / C90. Если вы нацелены на код, совместимый с C89, лучшее, что вы можете сделать, это привести unsigned longи использовать lвместо него модификатор длины, например printf("the size is %lu\n", (unsigned long)size);; поддержка как C89, так и систем с size_tбольшим, чем longболее сложна и потребует использования ряда макросов препроцессора.
Адам Розенфилд
45

Да, есть. Это %zu(как указано в ANSI C99).

size_t size = 1;
printf("the size is %zu", size);

Обратите внимание, что size_tэто беззнаковое, поэтому %ldдвойная ошибка: неправильный модификатор длины и неправильный спецификатор преобразования формата. Если вам интересно, %zdэто для ssize_t(который подписан).

maxschlepzig
источник
1

MSDN сообщает, что Visual Studio поддерживает префикс «I» для кода, переносимого на 32- и 64-разрядные платформы.

size_t size = 10;
printf("size is %Iu", size);
Аркантос
источник
6
он специфичен для MS, что не соответствует стандартам, поэтому он не зависит от платформы
phuclv
@phuclv Действительно. И если он действительно говорит - как следует из ответа - «портативный», это даже хуже, чем я когда-либо знал о РС. Не то чтобы меня это удивило ... Я не из тех, кто отрицает, потому что кто-то приложил усилия, чтобы попытаться ответить на что-то, но все же этот ответ просто неправильный. Ах, я думаю, что понимаю идею здесь, в «портативном». Надо сказать, что он работает как для 32-битных, так и для 64-битных версий. Но, конечно, будет.
Pryftan