Подтвердить что ты не робот

Как использовать спецификатор "zd" с `printf()`?

Ищите пояснения по использованию "zd" с printf().

Конечно, следующее верно для C99 и позже.

void print_size(size_t sz) {
  printf("%zu\n", sz);
}

Спецификация C, кажется, позволяет printf("%zd\n", sz) зависимости от того, как он читается:

7.21.6.1 Функция fprintf

z Указывает, что следующий спецификатор преобразования d, i, o, u, x или X применяется к size_t или соответствующему аргументу целочисленного типа со знаком; или что следующий спецификатор преобразования n применяется к указателю на целочисленный тип со size_t соответствующий аргументу size_t. C11dr §7.21.6.1 7

Должно ли это быть прочитано как

  1. " z Указывает, что следующий спецификатор преобразования d... применяется к size_t или соответствующему аргументу со size_t целочисленного типа со знаком..." (оба типа) и " z Указывает, что следующий спецификатор преобразования u... применяется к size_t или соответствующий аргумент целочисленного типа со знаком... "(оба типа)

ИЛИ ЖЕ

  1. " z указывает, что следующий спецификатор преобразования d... применяется к соответствующему аргументу со знаком целого типа со знаком..." (только со знаком типа) и " z указывает, что следующий спецификатор преобразования u... применяется к size_t " (беззнаковый тип только).

Я использовал определение № 2, но теперь не уверен.

Что правильно, 1, 2 или что-то еще?

Если # 2 верно, то каков пример типа, который может использовать "%zd"?

4b9b3361

Ответ 1

printf с форматом "%zd" ожидает аргумент подписанного типа, который соответствует неподписанному типу size_t.

Стандарт C не предоставляет имя для этого типа или хороший способ определить, что это такое. Если size_t является typedef для unsigned long, например, тогда "%zd" ожидает аргумент типа long, но это не переносимое предположение.

Стандарт требует, чтобы соответствующие типы с подписью и без знака использовали одно и то же представление для неотрицательных значений, которые представляются в обоих типах. В сноске говорится, что это подразумевает, что они взаимозаменяемы как аргументы функции. Итак:

size_t s = 42;
printf("s = %zd\n", s);

должен работать, и должен печатать "42". Он будет интерпретировать значение 42 неподписанного типа size_t, как если бы он был соответствующего типа. Но на самом деле нет веских оснований для этого, поскольку "%zu" также правилен и четко определен, не прибегая к дополнительным языковым правилам. И "%zu" работает для всех значений типа size_t, включая те, которые находятся вне диапазона соответствующего подписанного типа.

Наконец, POSIX определяет тип ssize_t в заголовках <unistd.h> и <sys/types.h>. Хотя POSIX явно не говорит об этом, предположительно ssize_t будет подписанным типом, соответствующим size_t. Поэтому, если вы пишете код, специфичный для POSIX, "%zd" - это (вероятно) правильный формат для печати значений типа ssize_t.

Ответ 2

В соответствии с небольшим тестом, который я сделал, "zd" всегда истинно, но "zu" не работает для отрицательных чисел.

Тестовый код:

  #include <stdio.h>
  int main (void)
  {  int i;
     size_t uzs = 1;
     ssize_t zs = -1;
    for ( i= 0; i<5 ;i++, uzs <<= 16,zs <<= 16 )
    {
       printf ("%zu\t", uzs); /*true*/
       printf ("%zd\t", uzs); /*true*/

       printf ("%zu\t", zs); /* false*/
       printf ("%zd\n", zs); /*true*/
    }
    return 0;
}