【问题标题】:Some problem about inline function in VS2019VS2019内联函数的一些问题
【发布时间】:2019-12-09 08:30:40
【问题描述】:

我正在对 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++ 中,如果需要,内联定义的函数将发出一个函数 在翻译单元之间共享,通常通过将其放入 需要它的目标文件的公共部分。功能 必须在任何地方都有相同的定义,总是使用内联 限定符。

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

从每个定义中查找名称会找到相同的实体(之后 重载决议)

【问题讨论】:

  • source1和source2中inline_func的定义不同,应该会有错误 这会导致Undefined Behavior。如果我是对的,这违反了 ODR。另一个问题是标准是否要求诊断...
  • cppreference.com 找到:程序中可能有多个内联函数或变量的定义(C++17 起),只要每个定义出现在不同的翻译中单元和(对于非静态内联函数和变量(C++17 起))所有定义都是相同的。如果定义了具有外部链接的内联函数或变量(C++17 起)在不同的翻译单元中不同,行为是未定义的。没有提到诊断(或者我忽略了它)。
  • 第一句的结尾,“通常 [...]”,是作者的臆想。
  • “应该有错误”当然,你已经做到了。
  • @molbdnilo 到目前为止我还没有看到反例,你呢?

标签: c++ visual-studio language-lawyer inline msvc14


【解决方案1】:

来自this One Definition Rule (ODR) reference

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

[强调我的]

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

【讨论】:

  • 这是否意味着在头文件的内联函数中使用 #if 和宏是不好的,除非预处理结果在使用该头文件的任何潜在来源中肯定是相同的?
  • @jw_ 是的,这可能很糟糕。
【解决方案2】:

有趣的是,在 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);

不内联。它总是导致编译器发出 "Call" :/

我也是这样:

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

并且无论是否:

  • 传递的参数是立即数/字面量
  • 传递的参数是堆栈局部变量
  • 传递的参数是堆分配静态全局
  • 函数改为uint32_t f(void) { return 1; }

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

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

只是我的 2c

\o/ - “别开枪!”

【讨论】:

    猜你喜欢
    • 2011-05-06
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多