2012-06-23 13 views
5

voglio usare variabile a da foo.c in main.c, e scrivo:Cosa c'è di sbagliato in questo programma C usando la parola chiave extern?

foo.c 
#include <stdio.h> 

int a[] = {3, 2}; 

void foo() 
{ 
    printf("foo\taddress of a:%x\n", a); 
    printf("foo\tvalue of a[0]:%x\n", a[0]); 
} 

main.c 
#include <stdio.h> 

extern int *a; 

int main(void) 
{ 
    foo(); 
    printf("main\taddress of a : %x\n", a); 
    printf("main\tvalue of a[0] : %x\n", a[0]); 

    return 0; 
} 

e l'output risultato:

foo address of a:804a014 
foo value of a[0]:3 
main address of a : 3 
Segmentation fault (core dumped) 

perché?

+0

Stai utilizzando un sistema operativo a 64 bit? –

+0

@PaulR Io uso Ubuntu a 32 bit 12.04 –

risposta

8

Il tipo di a è int[2], non int*. Riprovare con

extern int a[2]; 

Il compilatore C Non è possibile digitare-check tra i file di origine. Pertanto, quando si dice int* a, il compilatore assumerà che si sta dicendo la verità, utilizzare la semantica del puntatore e non genererà alcun errore del compilatore.

C'è una sottile differenza tra array e puntatori. Supponiamo un sistema a 32 bit. Poi il contenuto di "a" verrà distribuito in questo modo:

 
    a 
0x100  0x104  0x108 ← address 
    +-----------+----------+ 
    |   3 |  2 | ← content 
    +-----------+----------+ 

Quando a è un matrice,

  • Il valore dell'espressione a si sarà convertito l'indirizzo della a. Pertanto, quando si stampa a, si otterrà il suo indirizzo, ad esempio "0x100".
  • L'operazione a[n] in C equivale a *(a + n), ad esempio, anticipare l'indirizzo a da n unità e quindi dereferenziarlo per ottenere il contenuto. Pertanto, a[0] equivale a *0x100, che restituisce il contenuto a 0x100, ad esempio "3".

Quando a è un puntatore,

  • Il "valore" della a è il contenuto all'indirizzo fornito. In realtà questa è la norma, il tipo di array è un caso speciale. Pertanto, quando si stampa a, si otterrà il contenuto a quell'indirizzo, ad esempio "3".
  • L'operazione a[n] è ancora *(a + n). Pertanto, a[0] equivale a *3, che causa un errore di segmentazione perché l'indirizzo "3" non è valido.
+0

Ma anche "int a [2]" è puntatore, ad eccezione del compilatore che sa solo della sua dimensione in fase di compilazione. O la mia comprensione è sbagliata qui? –

+0

Ma questo programma può essere compilato correttamente, nessun errore. –

+4

@NiklasR: No 'int a [2]' non è un puntatore, è un array. 'extern int a [];' funzionerebbe bene quindi la differenza non è la dimensione conosciuta. –

1

È necessario utilizzare tipi coerenti per oggetti dichiarati in diverse unità di traduzione.

Dato int a[] = {2, 3};, una delle dichiarazioni extern int a[]; o extern int a[2]; sarebbe compatibile considerando che extern int *a; non sarebbe come puntatori e matrici sono tipi completamente separati.

L'unica cosa speciale sui gruppi è il quando il nome di un array appare in qualsiasi contesto espressione diverso come operando a "indirizzo" (unario &) o sizeof, essi vengono convertiti automaticamente a un puntatore alla loro prima elemento.Questo è ciò che fornisce la compatibilità della sintassi tra array e puntatori, ma non sono dello stesso tipo.

Considerare queste due funzioni per un esempio commentato. Notare che l'espressione a viene convertita in un puntatore al suo primo elemento nella seconda (e tecnicamente terza) printf della prima funzione, ma non nel primo printf dove è l'operando su &.

#include <stdio.h> 

void print_array_info(void) 
{ 
    extern int a[]; 
    printf("address of a: %p\n", (void*) &a); // prints address of a 
    printf(" converted a: %p\n", (void*) a); // prints address of a[0] 
    printf("value of a[0]: %x\n", a[0]);   // prints value of a 
} 

void print_pointer_info(void) { 
    extern int a[]; 
    int *b = a; // == &a[0] 

    printf("address of b: %p\n", (void*) &b); // prints address of b 
    printf(" value of b: %p\n", (void*) b); // prints value of b (== &a[0]) 
    printf("value of b[0]: %x\n", b[0]);  // prints value of b[0] (== a[0]) 
} 

Nota che uso %p stampare puntatori ed esplicitamente gettato a void*.