如果C++的inline函数中有宏,行为是怎样的?
天蓬老师
天蓬老师 2017-04-17 14:39:14
0
4
633

这里是几份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),还是未定义行为呢?

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

reply all(4)
洪涛

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) 
大家讲道理

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.

大家讲道理

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

黄舟

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

under any optimization switch

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 ;imp2imp2

The explanation is as follows:

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__

Except for member functions, if an ordinary inline function (non-member, non-static-member) is defined in a header file, it will cause a compilation error due to redefinition; while it will not occur at all if it is defined in cpp Affected by macros in other files.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template