1

C++ の内部リンケージと外部リンケージを理解するためにコードをいじっていました。リンクされている順序によって出力が異なるように見えるコードを思いつきました。


test1.cpp

#include<iostream>
using namespace std;
inline int c()
{
     static int p=0;
     p++;
     return p;
}
void a()
{
     cout<<"\nIn function a() , c = "<<c();
}


test2.cpp

#include<iostream>
using namespace std;

inline int c()
{
    static int p=12;
    p++;
    return p;
}

void b()
{
       cout<<"\nIn function b() , c = "<<c();
} 


ドライバー.cpp

#include<iostream>
using namespace std;

void a();
void b();
int c();

int main()
{
   b();
   a();
   a();
   b();
   cout<<"\nIn function main() = , c "<< c();
   cout<<"\n";
}

出力 1 :-

when compiles as follows :- 

bash#>g++ -c test1.cpp
bash#>g++ -c test2.cpp
bash#>g++ -c driver.cpp

bash#>g++ -o out driver.o test1.o test2.o
bash#>./out

In function b() , c = 1
In function a() ,  c = 2
In function a() ,  c = 3
In function b() , c = 4
IN main() , c = 5

上記の出力では、コンパイラは test1.cpp で定義された c() を考慮しています。

出力 2:- リンク中に test1.o と test2.o のシーケンスを変更します。

bash#>g++ -o out driver.o test2.o test1.o

In function b() , c = 13
In function a() ,  c = 14
In function a() ,  c = 15 
In function b() , c = 16
IN main() , c = 17

上記の出力では、コンパイラは test2.cpp で定義された c() を考慮しています。

コードに小さな変更を加えたとき、私は当惑しました。次のとおりです
。 cpp]

//test1.cpp changes
void a()
{
   cout<<"\nIn function a() , c = "; // not calling c()
}

//test2.cpp changes
void b()
{
    cout<<"\nIn function b() , c = "; // not calling c()
} 

リンク中に次のエラーが発生します:-

bash#>g++ -o out driver.o test1.o test2.o
driver.o: In function `main':
driver.cpp:(.text+0x1f): undefined reference to `c()'
collect2: ld returned 1 exit status

2) ファイルのいずれか、つまり test1.cpp または test2.cpp で c() を呼び出すと、リンカー エラーが発生しません。

誰でもこの動作を理解するのを手伝ってくれませんか。

前もって感謝します。

4

1 に答える 1

3

あなたのプログラムは、1 つの定義規則に違反しているため、未定義の動作をしています。2 つの異なる翻訳単位が、同じ名前と署名を持つ関数を定義していますが、本体は異なります。

C++11 標準のパラグラフ 3.2/6 によると:

[...] そのようなエンティティD が複数の翻訳単位で定義されている場合、

— の各定義はD、同じ一連のトークンで構成されるものとします。と

[...]

function はin andc()として宣言されているが、 in では宣言されていないため、プログラムの形式も正しくありません。パラグラフ7.1.2/4によるinlinetest1.cpptest2.cppdriver.cpp

[...] 外部リンケージを持つ関数が1 つの翻訳単位で宣言されている場合、それが現れるすべての翻訳単位でinline宣言されなければなりません。inline診断は必要ありません。[...]

診断は必要ありません」ビットは、コンパイラ (またはリンカ) がこの規則の違反に対してエラーを報告する場合と報告しない場合があることを意味します。つまり、壊れないように細心の注意を払う必要があります。

于 2013-05-26T15:57:20.417 に答える