簡單程式碼 為什麼#include<stdio.h>不需要使用printf()?




簡單程式碼 (3)

在嚴格的合規模式(這意味著“在理論上”)中,當您調用一個函數時調用未定義的行為(這是不好的),該函數接受可變數量的參數而沒有函數的原型聲明。 這意味著允許編譯器對使用printf()的程序執行任何操作,而不使用#include <stdio.h>的原型或等效聲明。 “任何牠喜歡的東西”包括正確地作為選項之一; 這似乎是你的例子選擇的選項。

在實踐中,即使沒有printf()函數的正式聲明,代碼也可以與大多數實用的編譯器一起使用。

正如qrdl所指出的,找到了該函數,因為C編譯器與C庫鏈接。

請注意,Chris Young關於C99和'implicit int'的評論是準確的,但關於'變量參數函數必須在範圍內具有原型'的規則適用於C89和C99。 默認情況下,大多數編譯器不能在嚴格的C99兼容模式下工作,因為有太多代碼無法像這樣編譯。

Chris Young評論道:

為了澄清,我的評論是關於C99刪除隱式聲明。 通過說“隱式int”,我認為你指的是允許聲明的C89特性,如foo(void); 意思是int foo(void);, C99也刪除了。

克里斯當然是正確的。 從C99標準中刪除了兩個“隱式聲明”功能。 標準的前言將它們列為:

  • 刪除隱式int
  • 刪除隱式函數聲明

我沒有想清楚(因而也沒有寫作)。 儘管如此,C89和C99都需要一個範圍原型,用於採用可變數量參數的函數。

為了顯示:

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

如果沒有第一行,這是一個正確的C89片段,其函數pqr()的隱式聲明作為返回整數(帶有未指定參數)的函數。 如果第一行被extern pqr();替換extern pqr(); ,這是一個正確的C89片段,其中pqr()的顯式聲明作為返回整數(帶有未指定參數)的函數,但返回類型為'implicit int '。 如上所述,該函數是顯式聲明的,並且具有顯式的int返回類型 - 但它仍然具有未指定的參數。 我認為這是有效的C99 - 儘管不是完全可取的。 當然,GCC(3.4.4)接受選項' -std=c99 -pedantic '。理想情況下,函數聲明應該包含完整的原型。(如果pqr()是用省略號定義的,那麼原型將是必需的在理論上 !)

會議記錄:

>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

你最初標記過這個C ++,但它似乎是一個C程序。 如果範圍內沒有原型(例如由於省略#include <stdio.h>),C將自動為函數提供隱式聲明。 隱含聲明將是:

int printf();

這意味著printf是一個返回int的函數,可以接受任意數量的參數。 這個原型恰好適合您的通話。 你應該#include <stdio.h>

最後,我應該補充說,當前的C標準(ISO / IEC 9899:1999或通俗地說“C99”)不允許隱式聲明,並且該程序不符合。 刪除了隱式聲明。 我相信你的編譯器不支持C99。 C ++也需要正確的原型,不進行隱式聲明。


printf()位於標準C庫中,鏈接器始終將標準庫鏈接到您的可執行文件,因此將找到任何標準函數,並且不會出現鏈接問題。

未能包含適當的頭導致使用非原型的函數可能導致問題,因為C編譯器假定沒有prototype的函數返回int並且接受可變數量的參數。 所以總是包括標題 - 這是你的安全圍欄。





declaration