这里是几份C++代码:
a.h
#include <iostream>
#ifndef STR
#define STR "default"
#endif
struct A {
static void print() { std::cout << STR; }
};
imp1.cc
#define STR "imp1"
#include "a.h"
void imp1() { A::print(); }
imp2.cc
#define STR "imp2"
#include "a.h"
void imp2() { A::print(); }
main.cc
void imp1();
void imp2();
int main() { imp1(); imp2(); }
我们知道,在类定义中定义的函数默认是inline函数,inline函数将建议编译器在行内展开代码。那么main打印的是imp1, imp2还是str?
我找不到相关的资料。相同的代码,编译命令为g++ main.cc imp1.cc imp2.cc
时,在GCC 6.1.1上面是打印imp1imp2
,在MinGW GCC 4.8.1上面是打印imp1imp1
。在编译命令为g++ imp2.cc imp1.cc main.cc
,在GCC 6.1.1上面没有变化,在MinGW GCC 4.8.1上面是打印imp2imp2
。
请问C++ standard有相关规定(也就是说是MinGW的bug),还是未定义行为呢?
試してみました。gcc を -O2 または -O1 で最適化すると、結果は imp1imp2 になります。-O0 で最適化すると、結果は imp1imp1 または imp2imp2 になります。
その理由は、デバッグを容易にするために -O 最適化を行わないと、インラインが gcc によって無視されるためです。
標準のインラインは、必須要件ではなく提案であるべきです。インラインを使用しない場合、.o ファイルの順序が決定要因になります。
GCC はインラインで実行されないはずです (たとえインラインで記述したとしても、コンパイラーはリンク段階で A::print への参照を実行することを保証しません)。 .o ファイルは A:: 印刷可能 (すべて弱いシンボル) に使用されますが、使用されるのは 1 つだけです。
投稿者はコンパイル プロセスを理解する必要があります。
1. コンパイル
3. リンク p>
define は前処理段階にあります
inline はコンパイル段階にあります
これで明らかになるはずです
環境:
clang -O0 -O1 の結果は
imp1imp1
になりますclang -O2 -O3 の結果は
imp1imp2
になりますインライン化を強制するようにコードを変更しました。
最適化スイッチでは
です。imp1imp2
コードがインライン展開を強制的に禁止している場合:
結果はファイルの順序に関連しています。
imp1.cpp
が最初にある場合、最適化スイッチではimp1imp1
になります。code> imp2.cpp が最初にランク付けされ、最適化スイッチの下では
imp2imp2
になります。説明は次のとおりです。
インライン化が強制されている場合、インライン関数のマクロは 2 つのファイルで独立して置き換えられます。
インライン化が無効な場合、インライン関数のマクロは次のようにコンパイルされます。最初のユニットが置き換えられます (複数のコンパイル単位で置き換えられた場合、インライン化と同等になるため)。
強制されない場合 (
__attribute__
がない場合)、コンパイラは -O0 -O1 でインライン化をオフにし、-O2 -O3 でのみインライン化をオンにします。メンバ関数を除き、通常のインライン関数(非メンバ、非静的メンバ)をヘッダファイルに定義すると再定義によりコンパイルエラーが発生しますが、再定義した場合はコンパイルエラーは発生しません。 cpp で定義されている 他のファイルのマクロの影響を受けます。