search

Home  >  Q&A  >  body text

如果C++的inline函数中有宏,行为是怎样的?

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

天蓬老师天蓬老师2767 days ago613

reply all(4)I'll reply

  • PHP中文网

    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) 

    reply
    0
  • 大家讲道理

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

    reply
    0
  • 大家讲道理

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

    reply
    0
  • 黄舟

    黄舟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

    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 < under any optimization switch 🎜>;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.

    reply
    0
  • Cancelreply