web-dev-qa-db-fra.com

Comment utiliser le spécificateur "zd" avec `printf ()`?

Vous cherchez des éclaircissements sur l'utilisation de "zd" avec printf().

Ce qui suit est certainement correct avec C99 et les versions ultérieures.

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

La spécification C semble autoriser printf("%zd\n", sz) en fonction de la façon dont elle est lue:

7.21.6.1 La fonction fprintf

z Spécifie qu'un spécificateur de conversion d, i, o, u, x ou X suivant s'applique à un size_t ou à l'argument de type entier signé correspondant; ou qu'un spécificateur de conversion n suivant s'applique à un pointeur sur un type entier signé correspondant à l'argument size_t. C11dr §7.21.6.1 7

Cela devrait-il être lu comme

  1. "z Spécifie qu'un spécificateur de conversion d ... suivant s'applique à un size_t ou à l'argument de type entier signé signé ..." (les deux types) et "z Spécifie qu'un spécificateur de conversion u ... suivant s'applique à un size_t ou au argument de type entier signé signé ... "(les deux types)

OR

  1. "z Spécifie qu'un spécificateur de conversion d ... suivant s'applique à un argument de type entier signé signé ..." (type signé uniquement) et "z ... Spécifie qu'un spécificateur de conversion u ... suivant s'applique à un size_t" (type non signé seulement).

J'utilise la définition n ° 2, mais maintenant je ne suis pas sûr.

Lequel est correct, 1, 2 ou autre chose?

Si # 2 est correct, quel est un exemple de type pouvant utiliser "%zd"?

12
chux

printf avec un format "%zd" attend un argument du type signé qui correspond au type non signé size_t.

La norme C ne donne pas de nom pour ce type ou un bon moyen de déterminer ce que c'est. Si size_t est un typedef pour unsigned long, par exemple, alors "%zd" attend un argument de type long, mais ce n'est pas une hypothèse portable.

La norme exige que les types signés et non signés correspondants utilisent la même représentation pour les valeurs non négatives représentables dans les deux types. Une note de bas de page indique que cela est censé impliquer qu'ils sont interchangeables en tant qu'arguments de fonction. Donc ça:

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

devrait fonctionner et devrait afficher "42". Il interprétera la valeur 42, du type non signé size_t, comme s'il s'agissait du type signé correspondant. Mais il n’ya vraiment aucune bonne raison de le faire, puisque "%zu" est également correct et bien défini, sans recourir à des règles de langage supplémentaires. Et "%zu" fonctionne pour les valeurs all de type size_t, y compris celles situées en dehors de la plage du type signé correspondant.

Enfin, POSIX définit un type ssize_t dans les en-têtes <unistd.h> et <sys/types.h> . Bien que POSIX ne le dise pas explicitement, on suppose que ssize_t sera le type signé correspondant à size_t. Donc, si vous écrivez du code spécifique à POSIX, "%zd" est (probablement) le format correct pour l’impression du type ssize_t.

14
Keith Thompson

Selon le petit test que j'ai fait, "zd" est toujours vrai, mais "zu" ne fonctionne pas pour les nombres négatifs.

Code de test:

  #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;
}
0
user3177100