statement Come utilizzare correttamente la parola chiave extern in C



extern c visual studio (8)

La mia domanda riguarda quando una funzione deve essere referenziata con la parola chiave extern in C.

Non riesco a vedere quando questo dovrebbe essere usato nella pratica. Mentre sto scrivendo un programma, tutte le funzioni che uso sono rese disponibili attraverso i file header che ho incluso. Quindi, perché sarebbe utile extern per ottenere l'accesso a qualcosa che non è stato esposto nel file di intestazione?

Potrei pensare a come l' extern funziona in modo non corretto, e in tal caso correggimi.

Modifica: Dovresti extern qualcosa quando è la dichiarazione predefinita senza la parola chiave in un file di intestazione?


Answer #1

È già stato affermato che la parola chiave extern è ridondante per le funzioni.

Per quanto riguarda le variabili condivise tra unità di compilazione, dovresti dichiararle in un file di intestazione con la parola chiave extern, quindi definirle in un unico file sorgente, senza la parola chiave extern. Il singolo file sorgente dovrebbe essere quello che condivide il nome del file di intestazione, per le migliori pratiche.


Answer #2

Tutte le dichiarazioni di funzioni e variabili nei file di intestazione dovrebbero essere extern .

Le eccezioni a questa regola sono le funzioni inline definite nell'intestazione e le variabili che, sebbene definite nell'intestazione, dovranno essere locali all'unità di traduzione (il file di origine in cui viene inclusa l'intestazione): queste dovrebbero essere static .

Nei file di origine, extern non deve essere utilizzato per funzioni e variabili definite nel file. Basta prefisso le definizioni locali con static e non fare nulla per le definizioni condivise - per impostazione predefinita saranno simboli esterni.

L'unica ragione per utilizzare extern in un file sorgente è dichiarare funzioni e variabili definite in altri file di origine e per le quali non viene fornito alcun file di intestazione.

Dichiarare i prototipi di funzione extern realtà non è necessario. Ad alcuni non piace perché sprecherebbe spazio e le dichiarazioni di funzione hanno già la tendenza a superare i limiti di linea. Ad altri piace perché in questo modo, funzioni e variabili possono essere trattati allo stesso modo.


Answer #3

Molti anni dopo, scopro questa domanda. Dopo aver letto tutte le risposte e i commenti, ho potuto chiarire alcuni dettagli ... Questo potrebbe essere utile per le persone che arrivano qui attraverso la ricerca degli occhiali.

La domanda riguarda specificamente l'uso delle funzioni "extern", quindi ignorerò l'uso di "extern" con le variabili globali.

Definiamo 3 prototipi di funzioni

//--------------------------------------
//Filename: "my_project.H"
extern int function_1(void);
static int function_2(void);
       int function_3(void);

Il file di intestazione può essere utilizzato dal codice sorgente principale come segue

//--------------------------------------
//Filename: "my_project.C"
#include "my_project.H"

void main(void){
    int v1 = function_1();
    int v2 = function_2();
    int v3 = function_3();
}

int function_2(void) return 1234;

Per compilare e collegare, dobbiamo definire "function_2" nello stesso file di codice sorgente in cui chiamiamo tale funzione. Le altre due funzioni potrebbero essere definite in un diverso codice sorgente " .C" oppure potrebbero trovarsi in qualsiasi file binario ( .OBJ, * .LIB, * .DLL), per il quale potremmo non avere il codice sorgente.

Consente di includere nuovamente l'intestazione "my_project.H" in un diverso file "* .C" per capire meglio la differenza. Nello stesso progetto, aggiungiamo il seguente file // --------------------------------------

//Filename: "my_big_project_splitted.C"
#include "my_project.H"

void old_main_test(void){
    int v1 = function_1();
    int v2 = function_2();
    int v3 = function_3();
}

int function_2(void) return 5678;

int function_1(void) return 12;
int function_3(void) return 34;

Caratteristiche importanti da notare: quando una funzione è definita come "statica" in un file di intestazione, il compilatore / linker deve trovare un'istanza di una funzione con quel nome in ogni modulo che usa quel file di inclusione.

Una funzione che fa parte della libreria C può essere sostituita in un solo modulo ridefinendo un prototipo con "statico" solo in quel modulo. Ad esempio, sostituire qualsiasi chiamata a "malloc" e "gratuita" per aggiungere funzionalità di rilevamento perdite di memoria.

Lo specificatore "extern" non è realmente necessario per le funzioni. Quando "statico" non viene trovato, si presume sempre che una funzione sia "esterna".

Tuttavia, "extern" non è l'impostazione predefinita per le variabili. Normalmente, qualsiasi file di intestazione che definisce le variabili per essere visibile su molti moduli deve usare "extern". L'unica eccezione sarebbe se un file di intestazione è garantito per essere incluso da uno e solo un modulo.

Molti project manager richiedono quindi che tale variabile sia posizionata all'inizio del modulo, non all'interno di alcun file di intestazione. Alcuni progetti di grandi dimensioni, come l'emulatore di videogiochi "Mame", richiedono addirittura che tale variabile appaia solo sopra la prima funzione che li utilizza.


Answer #4

" extern " cambia il collegamento. Con la parola chiave, si presume che la funzione / variabile sia disponibile da qualche altra parte e la risoluzione viene rimandata al linker.

C'è una differenza tra "extern" sulle funzioni e sulle variabili: sulle variabili non istanzia la variabile stessa, cioè non alloca memoria. Questo deve essere fatto da qualche altra parte. Quindi è importante se vuoi importare la variabile da qualche altra parte. Per le funzioni, questo dice solo al compilatore che il collegamento è esterno. Poiché questo è l'impostazione predefinita (si utilizza la parola chiave "statico" per indicare che una funzione non è associata utilizzando il collegamento extern) non è necessario utilizzarla esplicitamente.


Answer #5

extern dice al compilatore che questi dati sono definiti da qualche parte e saranno connessi con il linker.

Con l'aiuto delle risposte qui e parlando con alcuni amici ecco l'esempio pratico di un uso di extern .

Esempio 1: per mostrare una trappola:

File stdio.h:

int errno;
/* other stuff...*/
myCFile1.c:
#include <stdio.h>

Code...
myCFile2.c:
#include <stdio.h>

Code...

Se myCFile1.o e myCFile2.o sono collegati, ciascuno dei file c ha copie separate di errno . Questo è un problema visto che lo stesso errno dovrebbe essere disponibile in tutti i file collegati.

Esempio 2 - La correzione.

File stdio.h:

extern int errno;
/* other stuff...*/
File stdio.c

int errno;
myCFile1.c:
#include <stdio.h>

Code...
myCFile2.c:
#include <stdio.h>

Code...

Ora, se sia myCFile1.o che MyCFile2.o sono collegati dal linker, entrambi puntano allo stesso errno . Quindi, risolvendo l'implementazione con extern .


Answer #6

Le funzioni effettivamente definite in altri file sorgente dovrebbero essere dichiarate solo nelle intestazioni. In questo caso, dovresti usare extern quando dichiari il prototipo in un'intestazione.

La maggior parte delle volte, le tue funzioni saranno una delle seguenti (più come una buona pratica):

  • statico (funzioni normali che non sono visibili al di fuori del file .c)
  • statico in linea (in linea dai file .c o .h)
  • extern (dichiarazione nelle intestazioni del prossimo tipo (vedi sotto))
  • [nessuna parola chiave di sorta] (funzioni normali cui è possibile accedere utilizzando le dichiarazioni extern)

Answer #7

Un ottimo articolo che ho trovato sulla parola chiave extern , insieme agli esempi: http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

Anche se non sono d'accordo sul fatto che l'uso di extern nelle dichiarazioni di funzioni sia ridondante. Questo dovrebbe essere un settaggio del compilatore. Quindi raccomando di usare l' extern nelle dichiarazioni di funzione quando è necessario.


Answer #8

Quando hai quella funzione definita su una dll o una lib diversa, in modo che il compilatore rimandi al linker per trovarlo. Il caso tipico è quando si chiamano funzioni dall'API del sistema operativo.





c