2008-12-03 7 views
24

Sesja zapis:Dlaczego #include <stdio.h> nie jest wymagane do korzystania z printf()?

>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 
+0

Należy zauważyć, że w C89/C90 należy podać wartość zwracaną z 'main()' .C99 pozwala pominąć 'return 0;' lub odpowiednik od końca 'main()'. –

Odpowiedz

28

W trybie ścisłej zgodności (to znaczy "w teorii") wywołujesz niezdefiniowane zachowanie (które jest złe), gdy wywołujesz funkcję, która pobiera zmienną liczbę argumentów bez prototypowej deklaracji funkcji w zakresie. Oznacza to, że kompilator może robić wszystko, co mu się podoba, używając programu, który używa printf() bez prototypu z #include <stdio.h> lub deklaracji równoważnej. "Wszystko, co lubi" obejmuje prawidłowe działanie jako jedna z opcji; to wydaje się być opcją wybraną przez twój przykład.

W praktyce kod będzie działał poprawnie z większością praktycznych kompilatorów, nawet bez formalnej deklaracji funkcji printf().

Jak wskazał qrdl, funkcja została znaleziona, ponieważ kompilator C łączy się z biblioteką C.

Należy zauważyć, że komentarz Chrisa Younga na temat C99 i "implicit int" jest dokładny, ale reguła dotycząca "funkcji zmiennych argumentów musi mieć prototyp w zakresie" dotyczy zarówno C89, jak i C99. Większość kompilatorów nie pracuje domyślnie w trybie ścisłej kompatybilności C99, ponieważ jest zbyt wiele kodu, który by się nie skompilował.

Chris Młoda komentuje:

Aby wyjaśnić, mój komentarz był na C99 usuwania ukrytych deklaracji. Mówiąc "implicit int", myślę, że odnosisz się do funkcji C89 zezwalania na deklaracje takie jak foo (void); to znaczy int foo (void) ;, coś C99 również zostało usunięte.

Chris jest, oczywiście, poprawny. Z normy C99 usunięto dwie cechy "ukrytej deklaracji".Przedmowa do normy wymienia je jako:

  • usunąć niejawny int
  • usunąć niejawny deklarację funkcji

nie myślałem (i stąd nie pisania) wystarczająco jasno. Niemniej jednak zarówno C89, jak i C99 wymagają prototypu w zakresie funkcji, które pobierają zmienną liczbę argumentów.

Dla ilustracji

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

bez pierwszej linii, to jest fragment o właściwej C89 z domniemanym zgłoszenia funkcji pqr() jako funkcję, która zwraca całkowitą (z nieokreślonymi argumentów). Jeśli pierwszy wiersz zostanie zastąpiony przez extern pqr();, jest to poprawny fragment C89 z jawną deklaracją pqr() jako funkcją zwracającą liczbę całkowitą (z nieokreślonymi argumentami), ale typem powrotu jest "niejawny int". Jak napisano, funkcja jest jawnie zadeklarowana i ma wyraźny typ zwracany int - ale wciąż ma nieokreślone argumenty. Uważam, że jest to ważne C99 - choć nie jest to całkowicie pożądane. Oczywiście, GCC (3.4.4) akceptuje to z opcjami "-std=c99 -pedantic". Idealnie, deklaracja funkcji powinna zawierać pełny prototyp. (I gdyby pqr() zostały zdefiniowane z elipsą, prototyp ten byłby wymagany w teorii!)

+0

Aby wyjaśnić, mój komentarz dotyczył C99 usuwania ukrytych rozbieżności. Mówiąc" niejawne int ", myślę, że odwołujesz się do funkcji C89 zezwalania na takie deklaracje, jak foo (void), to znaczy int foo (void) ;, coś C99 również zostało usunięte. – Chris

35

Trzeba było pierwotnie oznaczone ten C++, ale wydaje się być program C. C automatycznie dostarczy ukrytą deklarację dla funkcji, jeśli nie ma prototypu w zakresie (np. Z powodu pominięcia #include <stdio.h>). Domyślna deklaracja to:

int printf(); 

Znaczenie, że printf jest funkcją zwracającą wartość int i może przyjmować dowolną liczbę argumentów. Ten prototyp zadziałał w twoim telefonie. Należy #include <stdio.h>

Na koniec należy dodać, że obecny standard C (ISO/IEC 9899: 1999 lub potocznie "C99") robi nie pozwalają ukryte deklaracji, a ten program nie byłoby zgodne . Niejawne deklaracje zostały usunięte. Wierzę, że Twój kompilator nie obsługuje C99. C++ wymaga również poprawnych prototypów i nie wykonuje ukrytych deklaracji.

8

printf() znajduje się w standardowej bibliotece C, a linker zawsze łączy bibliotekę standardową z plikiem wykonywalnym, więc wszelkie standardowe funkcje zostaną odnalezione i nie będzie problemów z łączeniem.

Niewłączenie odpowiedniego nagłówka powoduje użycie funkcji, która nie została prototypowana, co może prowadzić do problemów, ponieważ kompilator języka C zakłada, że ​​funkcja bez prototypu zwraca wartość int i przyjmuje zmienną liczbę argumentów. Zawsze dołączaj nagłówek - to jest twój płot bezpieczeństwa.

+2

Not a 'variable number Argumenty "ale nieokreślona, ​​ale ustalona liczba argumentów: –

Powiązane problemy