簡體   English   中英

C - 函數的單一定義規則

[英]C - One-definition rule for functions

我是 C 的新手,讀到每個 function 可能只定義一次,但我似乎無法將其與我在控制台中看到的內容相協調。 例如,我能夠在沒有錯誤或警告的情況下覆蓋printf的定義:

#include <stdio.h>

extern int printf(const char *__restrict__format, ...) {
    putchar('a');
}

int main() {
    printf("Hello, world!");
    return 0;
}

因此,我嘗試查找標准中的單一定義規則,並在第 155 頁上找到第 6.9 (5) 節,其中說(強調):

外部定義是外部聲明,它也是 function(內聯定義除外)或 object 的定義。如果在表達式 [...] 中使用使用外部鏈接聲明的標識符,則在整個程序的某處應恰好是該標識符的一個外部定義; 否則,不得超過一個。

我對鏈接的理解非常不穩定,所以我不確定這是相關的條款還是“整個程序”的確切含義。 但是,如果我將“整個程序”理解為<stdio.h>中的所有內容 + 我的源文件,那么我是否應該被禁止在我的源文件中重新定義printf ,因為它已經在“整個程序”的早期定義"(即在程序的stdio位中)?


如果這個問題是一個騙局,我很抱歉,我找不到任何現有的答案。

C 標准沒有定義如果 function 有多個定義會發生什么。

……我不應該被禁止嗎……

C 標准對您的操作沒有管轄權。 它指定了 C 程序的解釋方式,而不是人類的行為方式。 雖然它的一些規則是用“shall”來寫的,但這並不是對程序員的命令,告訴他們他們可以做什么或不可以做什么。 它是一種修辭手段,用於指定 C 程序的語義。 C 2018 4 2 告訴我們它的實際含義:

如果違反了出現在約束或運行時約束之外的“應該”或“不應”要求,則行為未定義......

因此,當您提供printf的定義並且標准 C 庫提供 printf 的定義時, printf標准未指定會發生什么。 在通常的實踐中,可能會發生以下幾種情況:

  • linker 使用您的printf 庫中的printf沒有用到。
  • 編譯器具有printf的內置知識並使用它,盡管您定義了printf
  • 如果您的printf在一個單獨的源模塊中,並且該模塊被編譯並插入到一個庫中,那么程序使用哪個printf取決於庫指定給 linker 的順序。

雖然 C 標准沒有定義如果 function(或一般的外部符號)有多個定義會發生什么,鏈接器通常會這樣做。 通常,當一個 linker 處理一個庫文件時,它的行為是:

  • 檢查庫中的每個模塊。 如果該模塊定義了一個由先前並入的 object 模塊引用但尚未定義的符號,則將該模塊包含在 linker 正在構建的 output 中。 如果模塊未定義任何此類符號,則不要使用它。

因此,對於普通函數,出現在庫文件中的多個定義的行為是由 linker 定義的,即使它不是由 C 標准定義的。 (不過,可能會有一些復雜的情況。假設一個程序使用cossin ,並且 linker 已經包含一個定義cos的模塊,當它找到一個同時定義sincos的庫模塊時。因為 linker 有一個未解析的對sin的引用,它包括這個庫模塊,它引入了cos的第二個定義,導致多重定義錯誤。)

盡管 linker 的行為可能定義得很好,但這仍然存在編譯器具有關於標准庫函數的內置知識的問題。 考慮這個例子 在這里,我添加了第二個printf ,所以程序有:

printf("Hello, world!");
printf("Hello, world!\n");

程序 output 是“aHello, world.\n”。 這表明程序對第一個printf調用使用了您的定義,但對第二個printf調用使用了標准行為。 該程序的行為就好像在同一個程序中有兩個不同的printf定義。

查看匯編語言可以看出發生了什么。 對於第二次調用,編譯器決定,因為printf("Hello, world;\n"); 正在打印一個沒有轉換規范並以換行符結尾的字符串,它可以改用更高效的puts例程。 所以匯編語言對第二個printfcall puts 編譯器無法對第一個printf執行此操作,因為它沒有以換行符結尾,它puts自動添加。

請注意declarationdefinition 術語完全不同。

  • stdio.h 只提供declaration 因此,當您在文件中聲明/定義時,只要原型相似,就可以了。
  • 您可以在源文件中自由定義。 如果可用,最終程序將鏈接到您的而不是庫中的程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM