这里是几份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),还是未定义行为呢?
PHP中文网2017-04-17 14:41:14
I tried it. If gcc is optimized with -O2 or -O1, the result will be imp1imp2. If it is optimized with -O0, the result will be imp1imp1 or imp2imp2
The reason should be that inline will be ignored by gcc without -O optimization to facilitate debugging.
Inline in the standard should be a suggestion, not a mandatory requirement. Without inline, the order of the .o files becomes the deciding factor.
$ gcc -v
使用内建 specs。
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/6.1.1/lto-wrapper
目标:x86_64-pc-linux-gnu
配置为:/build/gcc-multilib/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release
线程模型:posix
gcc 版本 6.1.1 20160802 (GCC)
大家讲道理2017-04-17 14:41:14
It should be that GCC does not perform inline (even if you write inline, the compiler does not guarantee that it will perform inline). In this case, at the link stage, for the reference of A::print, which .o file is used for A:: Print is possible (all are weak symbols), but only one will be used.
大家讲道理2017-04-17 14:41:14
The poster needs to understand the compilation process,
1. Preprocessing
2. Compilation
3. Assembly
4. Linking
define in the preprocessing phase
inline in the compilation phase
This should make it clear
黄舟2017-04-17 14:41:14
Environment:
Apple LLVM version 8.0.0 (clang-800.0.38)
Target: x86_64-apple-darwin16.0.0
Thread model: posix
The result of clang -O0 -O1 is imp1imp1
The result of clang -O2 -O3 is imp1imp2
I modified the code to force the use of inlining:
struct A {
__attribute__((always_inline)) static void print() { std::cout << STR; }
};
It is imp1imp2
And when the code forcibly prohibits inlining:
struct A {
__attribute__((noinline)) static void print() { std::cout << STR; }
};
The result is related to the file order:
If imp1.cpp
is ranked first, it is imp1imp1
under any optimization switch;
If imp2.cpp
is ranked first, it is < under any optimization switch 🎜>;imp2imp2
When inlining is forced, the macros of the inline function will be replaced independently in the two files;
When inlining is disabled, the macros of the inline function will be compiled in the first The unit is replaced (because if it is replaced in multiple compilation units, it is equivalent to inlining).
When not forced (no
), the compiler will turn off inlining under -O0 -O1, and only turn it on under -O2 -O3. __attribute__