Chiamata di una funzione con il numero errato (o tipi) di argomenti è a n errore. Lo standard richiede l'implementazione per rilevare alcuni, ma non tutti.
Quello che lo standard chiama un'implementazione, è in genere un compilatore con un linker separato (e alcune altre cose), dove un compilatore traduce singole unità di traduzione (cioè un file sorgente preelaborato) in file oggetto, che in seguito vengono collegati insieme. Mentre lo standard non si distingue tra loro, i suoi autori lo hanno scritto con l'impostazione tipica in mente.
C11 (n1570) 6.5.2.2 "le chiamate di funzione", P2:
Se l'espressione che indica la funzione chiamata ha un tipo che include un prototipo, il numero di argomenti deve essere d'accordo con il numero di parametri. Ogni argomento deve avere un tipo tale che il suo valore possa essere assegnato a un oggetto con la versione non qualificata del tipo del parametro corrispondente.
Questo è in una sezione "vincoli", cioè, l'applicazione (in questo caso, che è il compilatore) deve lamentare e può interrompere definizione se un "deve" requisito viene violata.
Nel tuo caso, c'era un prototipo visibile, quindi gli argomenti della chiamata di funzione devono corrispondere a con il prototipo.
Requisiti simili si applicano per una definizione di funzione con una dichiarazione di prototipo nell'ambito; se la tua definizione di funzione non corrisponde al prototipo, il tuo compilatore deve dirlo. In altre parole, se si assicura che tutte le chiamate a una funzione e la definizione di quella funzione rientrino nello scopo dello stesso prototipo, viene indicato se vi è una mancata corrispondenza. Ciò può essere garantito se il prototipo si trova in un file di intestazione che è incluso da tutti i file con chiamate a quella funzione e dal file che contiene la sua definizione. Utilizziamo i file di intestazione con i prototipi proprio per questo motivo.
Nel codice visualizzato, questa verifica viene ignorata fornendo un prototipo non corrispondente e non includendo l'intestazione file2.h.
Ibid. p9:
Se la funzione è definita con un tipo non compatibile con il tipo (dell'espressione) puntato dall'espressione che denota la funzione chiamata, il comportamento non è definito.
Un comportamento non definito significa che il compilatore è libero di presupporre che non si verifichi e che non è necessario rilevare se lo fa.
E infatti, sulla mia macchina, i file oggetto generato dal file 2.c (Ho inserito un return 0;
per avere un qualche corpo di funzione), non differire se rimuovo uno degli argomenti della funzione, il che significa che il file oggetto non contiene alcuna informazione sugli argomenti e quindi un compilatore vedendo solo file2 .o e file1.c non ha alcuna possibilità di rilevare la violazione.
Hai detto sovraccarico, quindi cerchiamo di compilare file2.c (con due e tre argomenti) come C++ e guardare i file oggetto:
$ g++ file2_three_args.cpp -c
$ g++ file2_two_args.cpp -c
$ nm file2_three_args.o
00000000 T _Z3fooiii
$ nm file2_two_args.o
00000000 T _Z3fooii
Funzione foo
ha i suoi argomenti incorporato nel simbolo creato per questo (un processo chiamato nome mangling), il file oggetto porta effettivamente alcune informazioni sui tipi di funzione. Di conseguenza, otteniamo un errore in fase di collegamento:
$ cat file1.cpp
extern void foo(int x, int y);
int main(void) {
foo(1,2);
}
$ g++ file2_three_args.o file1.cpp
In function `main':
file1.cpp:(.text+0x19): undefined reference to `foo(int, int)'
collect2: error: ld returned 1 exit status
Questo comportamento sarebbe anche consentito per un'implementazione C, interruzione di traduzione è una manifestazione valida di comportamento non definito in fase di compilazione o collegamento tempo.
Il modo in cui l'overloading in C++ viene in genere eseguito in realtà consente i controlli al momento del collegamento. Quella C non ha il supporto integrato per l'overloading delle funzioni, e che il comportamento non è definito nei casi in cui il compilatore non può vedere le discrepanze di tipo, consente di generare simboli per funzioni senza informazioni di tipo.
La dichiarazione 'extern' è ridondante se il file di intestazione è incluso. Ma non fa male. – Gene
NON è incluso il file di intestazione – user1047069
Quindi è un programma mal strutturato, che è facile in C. Potrebbe essere l'autore ad usare l'esterno come misura temporanea e averlo dimenticato. O è un trucco a causa di alcuni conflitti causati dall'inclusione dell'intera intestazione. – Gene