Domanda

Trascrizione sessione:

>type lookma.c
int main() {
  printf("%s", "no stdio.h");
}

>cl lookma.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

lookma.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:lookma.exe
lookma.obj

>lookma
no stdio.h
È stato utile?

Soluzione

In modalità di conformità rigorosa (ciò significa "in teoria"), si invoca un comportamento indefinito (il che è negativo) quando si chiama una funzione che accetta un numero variabile di argomenti senza una dichiarazione prototipo della funzione nell'ambito. Ciò significa che al compilatore è consentito fare qualsiasi cosa gli piaccia con un programma che utilizza printf () senza il prototipo di #include < stdio.h > o una dichiarazione equivalente . " Tutto ciò che gli piace " include il corretto funzionamento come una delle opzioni; quella sembra essere l'opzione scelta dal tuo esempio.

In pratica, il codice funzionerà correttamente con la maggior parte dei compilatori pratici anche senza la dichiarazione formale della funzione printf () .

Come sottolineato da qrdl, la funzione è stata trovata perché il compilatore C si collega alla libreria C.

Si noti che il commento di Chris Young su C99 e "implicito int" è accurato, ma la regola relativa alle "funzioni con argomenti variabili deve avere un prototipo nell'ambito" si applica sia a C89 che a C99. La maggior parte dei compilatori non funzionano in una modalità di compatibilità C99 rigorosa per impostazione predefinita perché c'è troppo codice che non si compilerebbe in questo modo.

Chris Young ha commentato:

  

Per chiarire, il mio commento era su C99 che rimuoveva le dichiarazioni implicite. Dicendo "int implicito", penso che ti riferisci alla funzione C89 di consentire dichiarazioni come foo (void); per int int foo (vuoto) ;, qualcosa rimosso anche da C99.

Chris è, ovviamente, corretto. Sono state rimosse due funzioni di "dichiarazione implicita" dallo standard C99. La prefazione allo standard li elenca come:

  • rimuovi int
  • implicito
  • rimuove la dichiarazione di funzione implicita

Non pensavo (e quindi non scrivevo) abbastanza chiaramente. Tuttavia, sia C89 che C99 richiedono un prototipo nell'ambito delle funzioni che accettano un numero variabile di argomenti.

Per illustrare:

extern int pqr();
int main(void)
{
    int i = pqr(1, 3);
    return i;
}

Senza la prima riga, questo è un frammento C89 corretto con una dichiarazione implicita della funzione pqr () come funzione che restituisce un numero intero (con argomenti non specificati). Se la prima riga è sostituita da extern pqr (); , questo è un frammento C89 corretto con una dichiarazione esplicita di pqr () come funzione che restituisce un numero intero ( con argomenti non specificati), ma il tipo restituito è 'implicito int '. Come scritto, la funzione è esplicitamente dichiarata e ha un tipo di ritorno esplicito int - ma ha ancora argomenti non specificati. Credo che sia valido C99 - anche se non del tutto auspicabile. Certamente, GCC (3.4.4) lo accetta con le opzioni ' -std = c99 -pedantic " ;. Idealmente, la dichiarazione di funzione dovrebbe includere il prototipo completo. (E, se pqr () fosse definito con i puntini di sospensione, quel prototipo sarebbe richiesto in teoria !)

Altri suggerimenti

Originariamente avevi taggato questo C ++, ma sembrerebbe essere un programma C. C fornirà automaticamente una dichiarazione implicita per una funzione se non esiste un prototipo nell'ambito (ad esempio a causa dell'omissione di #include < stdio.h >). La dichiarazione implicita sarebbe:

int printf();

Significa che printf è una funzione che restituisce un int e può accettare qualsiasi numero di argomenti. Questo prototipo ha funzionato per la tua chiamata. Dovresti #include < stdio.h >

Infine, dovrei aggiungere che l'attuale standard C (ISO / IEC 9899: 1999 o colloquialmente "C99") non consente dichiarazioni implicite e questo programma non sarebbe conforme. Dichiarazioni implicite sono state rimosse. Credo che il tuo compilatore non supporti C99. Il C ++ richiede anche prototipi corretti e non rilascia dichiarazioni implicite.

printf () si trova nella libreria C standard e il linker collega sempre la libreria standard al tuo eseguibile, quindi verranno trovate tutte le funzioni standard e non ci saranno problemi di collegamento.

La mancata inclusione di risultati di intestazione appropriati nell'uso di funzioni non prototipate può causare problemi, poiché il compilatore C presuppone che la funzione senza prototipo restituisca int e accetta un numero variabile di argomenti. Quindi includi sempre l'intestazione: è la tua barriera di sicurezza.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top