2014-11-14 13 views
8

Ich sah von Code in einem Legacy-Projekt folgendes Stück.extern-Deklaration, T * v/s T []

/* token.c */ 
struct token id_tokens[MAX_TOKENS]; 

/* analyse.c (v1) */ 
extern struct token *id_tokens; /* Raised my eyebrow, id_token declares a pointer */ 

Ich bestand darauf analyse.c auf die Veränderung der Erklärung, wie unten zu enthalten:

/* analyse.c (v2) */ 
extern struct token id_tokens[]; /* I am happy with this. id_tokens declares array of unspecified size. */ 

Ich möchte v2 weil pointer to T nicht gleich wie array of T ist. Der Zähler meines Freundes argumentierte, dass das Verhalten von beiden gleich ist, also ist es egal, ob ich v1 und v2 verwende.

Frage 1: Hat Array von unvollständigen Typ in einen Zeiger führen?

Frage 2: Ist mein Freund richtig, dass beide Versionen verhaltensgemäß garantiert gleichwertig sind?

+1

Siehe [dies] (http://c-faq.com/aryptr/aryptr1.html) ** Array sind keine Zeiger ** Viele Duplikate, idk was ist Verwirrung, in gewisser Weise, Sie und Ihr Freund sind beide falsch – P0W

+0

Arrays und Zeiger können synonym verwendet werden, da ein Array nur eine Gruppe von Variablen desselben Typs in einer Zeile im Speicher darstellt und ein Zeiger einfach auf das erste Element einer Gruppe von Variablen desselben Typs in einer Zeile zeigt in Erinnerung. Deshalb ist 'char * foo' das gleiche wie' char foo [] ' – Gophyr

+0

@Gophyr Du redest die Sprache meines Freundes. Überprüfen Sie die Antworten unten. Sie sind tatsächlich anders. –

Antwort

2
/* token.c */ 
struct token id_tokens[MAX_TOKENS]; 

/* 
id_tokens 
    +-----+-----+-----+-----+...+-----+ 
    |  |  |  |  | |  | 
    +-----+-----+-----+-----+...+-----+ 
    [0] [1] [2] [3] ... [MAX_TOKEN-1] 

    To access id_tokens[i], add offset of ith element 
    i.e. i * sizeof(struct token) to the **address** 
    of array token 
*/ 

Also in Ihrem analyse.c, würden folgende Anweisungen dieser Erklärung erzeugt werden.

  1. extern struct token id_tokens[];
    id_tokens [i]
    a. Adresse von id_tokens, die von einer anderen Kompilierungseinheit verknüpft sein könnten, wird genommen
    b. Offset von i wird hinzugefügt
    c.Der Wert wird verwiesen
/* analyse.c (v1) */ 
extern struct token *id_tokens; 

/* 
id_tokens 
    +------+   +-----+... 
    | addr |---------->|  | 
    +------+   +-----+... 


    To access id_tokens[i], fetch **contetnts** of pointer 
    token, add offset of ith element i.e. i * sizeof(struct token) 
    is added to this. 
*/ 

Also in Ihrem analyse.c, würden folgende Anweisungen dieser Erklärung generiert werden:

  1. extern struct token *id_tokens;
    id_tokens [i]
    a. Es wird der Inhalt von der Adresse id_tokens genommen, die von der anderen Kompilierungseinheit verknüpft ist.
    (Führt zu einem Kompilierungsfehler, wenn er in der gleichen Kompilierungseinheit wegen eines nicht übereinstimmenden Typs vorhanden ist)
    b. Offset von i wird hinzugefügt
    c. Wert wird
  2. verwiesen

des sizeof Nehmen wir an, id_token[0] ist 2 Byte und sizeof Zeiger auf id_token[0]4 Byte ist.

Ihre spätere Erklärung kann (mis) interpretieren die id_tokens[0] & id_tokens[1] als Adresse und fügen Sie einige zu dieser versetzt (die eine vorhandene oder nicht vorhandene Adresse, ausgerichtet oder nicht-ausgerichtete Adresse, der weiß sein kann).

Wenn es Ihr guter Tag ist, kann das Programm sofort abstürzen oder segfault und Sie erhalten eine Chance, den Fehler zu beheben. Wenn es Ihr schlechter Tag ist, kann Programm gerade mit etwas anderem Gedächtnis durcheinander bringen oder einen falschen Zustand zu irgendeinem Modul mitteilen, das in den schwierigen Fehler führen kann und einen Albtraum verursacht.


Jetzt denke ich, Sie verstehen, warum Sie (nil) als Ausgabe in Mr. 32's answer bekam.

2

kann durch das Programm

test.c

#include<stdio.h> 
#include"head.h" 
struct token id_tokens[10]; 
int main() 
{ 
printf("In original file: %p",id_tokens); 
testing(); 
} 

head.h

struct token { 
int temp; 
}; 

test1.c mit v1

#include<stdio.h> 
#include"head.h" 
extern struct token* id_tokens; 
void testing() { 
printf("In other file %p",id_tokens); 
} 
gleichem Material verstehen

Ausgang: In Originaldatei: 0x601040In andere Datei (nil)


test1.c mit v2

#include<stdio.h> 
#include"head.h" 
extern struct token id_tokens[]; 
void testing() { 
printf("In other file %p",id_tokens); 
} 

Ausgang: In Originaldatei: 0x601040In andere Datei 0x601040


Dies zeigt deutlich t Hat v1 ist nicht korrekt und v2 ist korrekt.

+0

Das Nicht-Gilden von id_tokens zu 'void *' für '% p' ist UB. Warum ist es null? –

+0

In v1 haben Sie id_tokes als externen Zeiger auf das Strukturtoken deklariert, aber es gibt kein globales Strukturtoken in beiden Dateien, daher ist es null. –

+0

+1 Sehr pragmatische Art und Weise. Gibt es eine Spezifikationsreferenz, die dasselbe vorschlägt? –