2017-08-13 4 views
51

Dieses Programm soll die Elemente von array ausdrucken, aber wenn es ausgeführt wird, wird keine Ausgabe angezeigt.Schleife beginnt bei -1 druckt nichts

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

Warum zeigt dieses Programm keine Ausgabe?

+37

Ein Makro mit einem hartcodierten Variablennamen verlangt Probleme. – jackarms

+1

Ändern von 'd = 0 'gibt zwar Dinge aus –

+1

@TonyTannous, aber es erklärt nicht, was das Problem in der OP ist – CIsForCookies

Antwort

145

sizeof gibt eine vorzeichenlose Ganzzahl zurück, daher ist TOTAL_ELEMENTS ebenfalls vorzeichenlos.

d ist signiert. Anfänglich ist d-1. Wenn Sie jedoch den Vergleich durchführen, wird d implizit typecast zu unsigned, so dass es nicht mehr -1 ist, wenn es mit TOTAL_ELEMENTS verglichen wird, ist es tatsächlich UINT_MAX (das ist 4294967295 auf meiner Maschine, könnte aber für andere abweichen).

Auch

Wenn Sie dieses Problem beheben möchten, typisieren TOTAL_ELEMENTS zu int:

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

Dieser Druck wird:

23 
34 
12 
17 
204 
99 
16 

Wie man erwarten würde. Sie können auch unter Comparison operation on unsigned and signed integers nach weiteren Informationen zum Thema Signed-Unsigned-Vergleiche suchen.

Es ist erwähnenswert, dass auf Compiler-Warnungen drehen würde haben Sie herausfinden, geholfen, was los war (wie durch hyde in seiner comment beobachtet):

$ 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. 

Alternativ, warum nicht d starten unter 0 und laufen zu TOTAL_ELEMENTS - 1 stattdessen? Sie können sogar die Typumwandlung löschen, die nur für den Eckfall d = -1 erforderlich ist.

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

Als Fußnote, hier sind die entsprechenden C99 Standard-Auszüge:

  1. 6.3.1.8p2 definiert die Umwandlung von in unsigned Typ unterzeichnet.

    Wenn der Operand, der unsigned integer Typ hat Rang größer oder gleich dem Rang des Typs des anderen Operanden aufweist, dann der Operand mit signierten Integer-Typ auf den Typ des Operanden mit unsigned integer umgewandelt Art.

  2. 6.3.1.3p2 definiert, wie die Konvertierung abgeschlossen ist: Durch UINT_MAX + 1 zu der signierten Darstellung hinzufügen.

    Wenn der neue Typ unsigned ist, wird der Wert durch wiederholte umgewandeltes Hinzufügen oder ein mehr als der Maximalwert Subtraktion, die in dem neuen Typ dargestellt werden kann, bis der Wert in dem Bereich des neuen Typs.

    So -1 =>-1 + (UINT_MAX + 1) = UINT_MAX, für dieses Szenario.

35

Meine gcc gibt diese Warnung:

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

was bedeutet, dass (TOTAL_ELEMENTS-2)unsigned int während d ist signed int ist. Dies macht den Ausdruck immer false für den Anfangswert von d, seit (unsigned int)(-1) > (TOTAL_ELEMENTS-2).

+19

ja. Die Lektion: immer alle Warnungen aktivieren und sie lesen –

+1

Der Ausdruck ist nicht * immer falsch *, es ist falsch für den Anfangswert von 'd'. – chqrlie

4

Binäroperationen zwischen verschiedenen ganzzahligen Typen werden in einem "allgemeinen" Typ durchgeführt, der durch sogenannte gewöhnliche arithmetische Konvertierungen definiert wird. Also ist int d vom Typ singed mit dem Wert -1 initialisiert. Bei der Umwandlung in unsigned int gibt es das Maximum von unsigned int zurück, das viel viel größer als der Wert ist, der von TOTAL_ELEMENTS zurückgegeben wird.

+1

'unsigned int' in Ihrer Antwort sollte' size_t' sein. Abgesehen davon, Sie sind auf dem Punkt. – StoryTeller