簡體   English   中英

具有不同定義的內聯函數的不可預測行為

[英]unpredictable behavior of Inline functions with different definitions

我有以下源文件:

//test1.cpp
#include <iostream>
using namespace std;

inline void foo()
{
  cout << "test1's foo" << endl;
}

void bar();

int main(int argc, char *argv[])
{
  foo();
  bar();
}

//test2.cpp
#include <iostream>

using namespace std;

inline void foo()
{
    cout << "test2's foo" << endl;
}

void bar()
{
    foo();
}

輸出:

test1's foo
test1's foo

咦??? 好的,所以我應該聲明foos是靜態的...但是這種事情不應該產生鏈接器錯誤,或者至少是警告? 編譯器如何從編譯單元“看到”內聯函數?

編輯:這是使用gcc 4.4.1。

您正在遇到單定義規則 您沒有看到任何錯誤,因為:

[某些]違規行為,特別是那些跨越翻譯單位的行為,不需要被診斷出來

在幕后發生的事情是編譯器沒有內聯這些函數(除非使用優化器編譯代碼,否則許多編譯器不會內聯函數)。 由於函數是內聯的並且可以出現在多個轉換單元中,因此編譯器會將該函數標記為link-once,它告訴鏈接器它不會將多個定義視為錯誤,而只是使用其中一個。

如果你真的希望它們不同,你需要一個靜態函數。

R Samuel Klatchko的答案是正確的,但我會回答他沒有的答案。

“編譯器如何”看到“來自編譯單元的內聯函數?”

它沒有。 它看到聲明為不是靜態的函數的外部定義。 對於這樣的函數,編譯器可以內聯,如果它希望,但它也必須生成從外部可調用的代碼。

內聯函數放在COMDAT部分中。 這是鏈接器的一個信號,它可以自由選擇它遇到的多個定義中的任何一個。 當您反轉鏈接順序時,您將收到另一個輸出消息。

將定義放在COMDAT部分(允許編譯器)的另一種方法是:

__declspec(selectany) int globalVariableInHeader = 42;

這是避免“外部”歌曲和舞蹈的方便。 顯然,這種機制被設計為允許由一個頭文件引入的多個定義由多個源文件獲得#included由鏈接器解析。 Fwiw,MSVC具有完全相同的行為。

暫無
暫無

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

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