2010-08-13 7 views
89

Ich lese gerade einen Code und festgestellt, dass die Person arr[-2] wurde mit dem zweiten Element zuzugreifen, bevor die arr, etwa so:Sind negative Array-Indizes in C zulässig?

|a|b|c|d|e|f|g| 
     ^------------ arr[0] 
     ^---------- arr[1] 
    ^---------------- arr[-2] 

Ist das erlaubt?

Ich weiß, dass arr[x] ist das gleiche wie *(arr + x). Also arr[-2] ist *(arr - 2), was in Ordnung scheint. Was denken Sie?

Antwort

146

Das ist richtig. Von C99 §6.5.2.1/2:

Die Definition des Index Operator [] ist, dass E1 [E2] ist identisch mit (* ((E1) + (E2))).

Es gibt keine Magie. Es ist eine 1-1 Äquivalenz. Wie immer bei der Dereferenzierung eines Zeigers (*) müssen Sie sicherstellen, dass er auf eine gültige Adresse verweist.

+1

Beachten Sie auch, dass Sie den Zeiger nicht dereferenzieren müssen, um UB zu erhalten. Lediglich die Berechnung von 'irgendein Array-2' ist undefiniert, es sei denn, das Ergebnis liegt in dem Bereich vom Start von 'irgendein Array' bis 1 nach seinem Ende. – RBerteig

+20

In älteren Büchern wurden die '[]' als * Syntax Zucker * für Zeigerarithmetik referenziert. * Favorite * Weg, Anfänger zu verwechseln, ist '1 [arr]' - anstelle von 'arr [1]' zu schreiben - und ihnen beim Raten zuzusehen, was das bedeuten soll. – Dummy00001

+4

Was passiert auf 64-Bit-Systemen (LP64), wenn Sie einen 32-Bit-Int-Index haben, der negativ ist? Sollte der Index vor der Adressberechnung zu einem 64-Bit-Zeichen mit Vorzeichen hochgestuft werden? –

10

Klingt gut für mich. Es wäre ein seltener Fall, dass Sie es jedoch rechtmäßig brauchen würden.

+6

Es ist nicht * das * selten - es ist sehr nützlich in z.B. Bildverarbeitung mit Nachbarschaftsoperatoren. –

59

Dies ist nur gültig, wenn arr ein Zeiger ist, der auf das zweite Element in einem Array oder einem späteren Element zeigt. Andernfalls ist es nicht gültig, weil Sie auf Speicher außerhalb der Grenzen des Arrays zugreifen würden. So zum Beispiel, wäre dies falsch:

int arr[10]; 

int x = arr[-2]; // invalid; out of range 

Aber das wäre in Ordnung:

int arr[10]; 
int* p = &arr[2]; 

int x = p[-2]; // valid: accesses arr[0] 

Es ist jedoch ungewöhnlich, dass ein negativer Index zu verwenden.

+0

Ich würde nicht so weit gehen zu sagen, es ist ungültig, nur potenziell chaotisch –

+10

@Matt: Der Code im ersten Beispiel ergibt undefiniert Verhalten. –

+0

BSTR ist ein gutes Beispiel in Windows. Jeder Debug-Zuordner. Nichts ist falsch damit. –

7

Was wahrscheinlich war, dass arr auf die Mitte des Arrays zeigte, so dass arr[-2] auf etwas im ursprünglichen Array, ohne außerhalb der Grenzen zu zeigen.

7

Ich bin nicht sicher, wie zuverlässig das ist, aber ich habe gerade gelesen, die folgende Einschränkung über negativen Array-Indizes auf 64-Bit-Systemen (LP64 vermutlich): http://www.devx.com/tips/Tip/41349

Der Autor scheint zu sagen, dass 32-Bit-int Array-Indizes mit 64-Bit-Adressierung können zu fehlerhaften Adressberechnungen führen, wenn der Array-Index nicht explizit auf 64 Bit hochgestuft wird (z. B. über eine ptrdiff_t-Darstellung). Ich habe tatsächlich einen Fehler seiner Art mit der PowerPC-Version von gcc 4.1.0 gesehen, aber ich weiß nicht, ob es ein Compiler-Bug ist (dh sollte nach C99-Standard funktionieren) oder richtiges Verhalten (dh Index benötigt eine Umwandlung auf 64 Bits für korrektes Verhalten)?

+3

Das klingt wie ein Compiler-Bug. – tbleher

1

Ich weiß, die Frage ist beantwortet, aber ich konnte nicht widerstehen, diese Erklärung zu teilen.

Ich erinnere mich, Principles of Compiler Design, Nehmen wir an, eine ist ein int-Array und eine Größe von int 2, & Basisadresse für eine 1000.

Wie a[5] funktioniert ->

Base Address of your Array a + (index of array *size of(data type for array a)) 
Base Address of your Array a + (5*size of(data type for array a)) 
i.e. 1000 + (5*2) = 1010 

Diese Erklärung ist auch der Grund, warum negative Indizes in Arrays in C arbeiten.

dh wenn ich a[-5] es Zugang gibt mir

Base Address of your Array a + (index of array *size of(data type for array a)) 
Base Address of your Array a + (-5 * size of(data type for array a)) 
i.e. 1000 + (-5*2) = 990 

Es kehrt mich 990. Nach dieser Logik an der Stelle Objekt wir negative Indizes in Array in C

1

Über warum zugreifen jemand negativen Indizes verwenden wollen, ich habe sie in zwei Kontexten verwendet:

  1. eine Tabelle der kombinatorischen Nummern th at sagt dir kamm [1] [- 1] = 0; Sie können Indizes immer überprüfen, bevor Sie auf die Tabelle zugreifen, aber auf diese Weise sieht der Code sauberer aus und wird schneller ausgeführt.

  2. Putting ein Centinel am Anfang einer Tabelle. Zum Beispiel wollen Sie so etwas wie

    while (x < a[i]) i--; 
    

verwenden, aber dann sollten Sie auch prüfen, ob i positiv ist.
Lösung: machen Sie es so, dass a[-1] ist -DBLE_MAX, so dass x&lt;a[-1] wird immer falsch sein.

Verwandte Themen