Незалежні від платформи size_t Специфікатори формату в c?


86

Я хочу роздрукувати змінну типу size_tна C, але, схоже, 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, оскільки аргумент не підписаний.
кафе

Інші доступні варіанти пояснюються на сторінці керівництва 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(що підписано).


1

MSDN повідомляє, що Visual Studio підтримує префікс "I" для коду, що переноситься на 32 та 64 бітових платформах.

size_t size = 10;
printf("size is %Iu", size);

6
це специфічно для MS, що не відповідає стандартам, тому не є незалежним від платформи
phuclv

@phuclv Дійсно. І якщо це справді говорить - як відповідає відповідь - "портативний", це навіть гірше, ніж я коли-небудь знав про РС. Не те щоб це мене здивувало ... Я не з тих, хто голосував проти, тому що хтось намагався щось відповісти, але все-таки ця відповідь просто неправильна. Ах, я думаю, я розумію ідею тут, "портативний". Слід сказати, що він працює як для 32-розрядної, так і для 64-розрядної версій. Але, звичайно, було б.
Прифтан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.