web-dev-qa-db-fra.com

La boucle commençant à -1 n'imprime rien

Ce programme est censé imprimer les éléments de array, mais lorsqu’il est exécuté, aucune sortie n’est affichée.

#include <stdio.h>

#define TOTAL_ELEMENTS  (sizeof(array) / sizeof(array[0]))

int array[] = { 23, 34, 12, 17, 204, 99, 16 };

int main() {
    int d;
    for (d = -1; d <= (TOTAL_ELEMENTS - 2); d++) 
        printf("%d\n", array[d + 1]);
    return 0;
}

Pourquoi ce programme ne montre aucune sortie?

55
rohit kumar

sizeof renvoie un entier non signé, donc TOTAL_ELEMENTS est également non signé.

d est signé. Initialement, d est -1. Cependant, lors de la comparaison, d est implicitement transtypé en non-signé, il n'est donc plus -1 Comparé à TOTAL_ELEMENTS, Il s'agit en réalité de UINT_MAX (qui est 4294967295 sur ma machine, mais peut différer pour d'autres).

Également,

Si vous voulez résoudre ce problème, transtypez TOTAL_ELEMENTS En int:

for(d = -1; d <= (int)(TOTAL_ELEMENTS - 2); d++) 

Cela va imprimer:

23
34
12
17
204
99
16

Comme vous vous en doutez. Vous pouvez également consulter Opération de comparaison sur des entiers non signés et signés pour plus d'informations sur les comparaisons signée/non signée.

Il est à noter que le fait d'activer les avertissements du compilateur vous aurait aidé à comprendre ce qui se passait (comme l'observe hyde dans son commentaire ):

$ gcc -Wall -Wextra test.c
test.c:7:17: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
      for(d = 0; d < TOTAL_ELEMENTS; d++) 
              ~ ^ ~~~~~~~~~~~~~~
1 warning generated.

Sinon, pourquoi ne pas démarrer d à 0 Et exécuter à la place TOTAL_ELEMENTS - 1? Vous pouvez même supprimer la conversion de type, ce qui n’est nécessaire que pour la casse de coin de d = -1.

for(d = 0; d < TOTAL_ELEMENTS; d++) 
    printf("%d\n", array[d]);

En guise de note de bas de page, voici les extraits pertinents de la norme C99:

  1. 6.3.1.8p2 définit la conversion du type signé en type non signé.

    Si l'opérande qui a un type entier non signé a un rang supérieur ou égal au rang du type de l'autre opérande, l'opérande avec le type entier signé est converti au type de l'opérande avec le type entier non signé.

  2. 6.3.1.3p2 définit comment la conversion est effectuée: En ajoutant UINT_MAX + 1 À la représentation signée.

    Si le nouveau type n'est pas signé, la valeur est convertie en ajoutant ou en soustrayant de manière répétée une valeur de plus que la valeur maximale pouvant être représentée dans le nouveau type jusqu'à ce que la valeur se situe dans la plage du nouveau type.

    Donc -1 => -1 + (UINT_MAX + 1) = UINT_MAX, Pour ce scénario.

155
cs95

Mon gcc émet cet avertissement:

warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
      for(d = 0; d < TOTAL_ELEMENTS; d++) 

ce qui signifie que (TOTAL_ELEMENTS-2) est unsigned int tandis que d est signed int. Cela rend l'expression toujours false pour la valeur initiale de d, puisque (unsigned int)(-1) > (TOTAL_ELEMENTS-2).

39
CIsForCookies

Les opérations binaires entre différents types d'intégraux sont effectuées dans un type "commun" défini par les conversions arithmétiques usuelles. Donc, int d est de type singularisé initialisé avec la valeur -1. Lorsqu’il est converti en unsigned int, il retournera un maximum d’un unsigned int, ce qui est beaucoup plus grand que la valeur renvoyée par TOTAL_ELEMENTS.

5
Patt