1

我正在对 VS2019 中的 C++ 内联函数进行一些(可能是奇异的)实验:

来源1:

#include "pch.h"

inline int inline_func(int i) {
    return  i;
}

void testinline1()
{
    inline_func(0);
}

来源2:

#include "pch.h"

inline int inline_func(int i) {
    return  i*i ;
}

void testinline2()
{
    inline_func(0);
}

主要来源:

#include "pch.h"

inline int inline_func(int i);
int main(int argc,char* argv[])
{   
    int i = inline_func(2);
}

根据http://en.wikipedia.org/wiki/Inline_function的“内联函数的存储类”部分,

在 C++ 中,如果需要,内联定义的函数将发出一个在翻译单元之间共享的函数,通常通过将其放入需要它的目标文件的公共部分。该函数在任何地方都必须具有相同的定义,并且始终使用 inline 限定符。

source1 和 source2 中的 inline_func 的定义不同,所以应该会有错误,但是在 VS2019 中没有这样的错误。

main() 中 i 的结果是 2,它来自 source1 中的 inline_func,这似乎是构建过程的随机选择,因为如果我在 source1 中注释 testinline1,那么我将变为 4,因为 source1 中的 inline_func 不会显示在目标文件中而不在同一源中使用。当我在 source2 中评论 testinline2 时, inline_func 也会出现未定义的符号错误,如预期的那样。

为什么会发生这些?这是 C++ 不涵盖的地方还是只有 MSVC 不涵盖的地方?

回答后更新

这是一个更好的例子:

来源1:

#include "pch.h"

int non_inline_func();
inline int inline_func2() {
    return  non_inline_func();
}

static int non_inline_func()
{
    return 1;
}

int public_func1() 
{
    return inline_func2();
}

来源2:

#include "pch.h"

int non_inline_func();
inline int inline_func2() {
    return  non_inline_func();
}

static int non_inline_func()
{
    return 2;
}

int public_func2()
{
    return inline_func2();
}

主要来源:

#include "pch.h"

int public_func1();
int public_func2();

void TestInline()
{
    int i =public_func1();
    int j= public_func2();
}

结果是 i=j=1。内联函数的定义在这里是一样的。这应该违反:https ://en.cppreference.com/w/cpp/language/definition#One_Definition_Rule

每个定义中的名称查找找到相同的实体(在重载解析之后)

4

2 回答 2

4

这个单一定义规则(ODR)参考

如果满足所有这些要求,则程序的行为就好像整个程序中只有一个定义。否则,程序格式错误,不需要诊断

[强调我的]

如果您有 ODR 违规(因为这两个定义不相同),编译器不必发出警告或错误消息。

于 2019-12-09T08:37:45.327 回答
0

有趣的是,在 MSVS2019 ISO C++ 14...

内联函数:

inline uint32_t hanoi(int a) { __asm  bsf eax, a } // Solve arbitrary 'Tower of Hanoi' round

使用以下任一方式调用:

int numMoves = (1<<numDisks)-1; /* Calculate number of moves needed to solve */

// Print full Tower Of Hanoi solution
for (int i = 1;i < numMoves;i++) {
    printf("move disk %u %s\n", hanoi(i), hanoi(i) & 1 ? "left" : "right");
}

要不就 :

hanoi(1);

不内联。它总是导致编译器发出“调用” :/

我也一样:

  • 像个好孩子一样使用 std::cout ... )
  • 直接调用函数(丢弃)或;
  • 直接调用函数(利用返回值)

并且无论是否:

  • 传递的参数是立即数/字面量
  • 传递的参数是堆栈局部变量
  • 传递的参数是堆分配的静态全局
  • 功能改为uint32_t f(void) { return 1; }<--让我惊讶!

我注意到那些比我更聪明的人抱怨 VS2015 和 VS2017 中的类似内联问题 - 每个人都将其与 CLANG 和 GCC 中的相同代码进行比较,他们的编译器似乎没有任何问题:/每次 MS 似乎都有将其识别为编译器问题。

TBH,看起来 VS 在内联函数方面可能有点“脆弱”:(

只是我的2c

\o/ - “不要开枪!”

于 2021-02-04T15:58:37.623 回答