3

有人可以解释此用户错误导致不一致崩溃的幕后原因。

这里是主要功能

#include "foo.h"  
inline int Bar(const int &a)  
{  
...  
}  
...  
int b=Bar(a);

在“foo.C”中还有一个函数的副本

inline int Bar(const int &a) 

这是问题所在。我既没有 foo.h 也没有 foo.C,并且 foo.h 中没有 Bar(int) 的声明。
在我的同事更新了他的 foo.C 中的一些其他函数之后,一切都可以编译并与旧版本的 foo.h 和 foo.C 一起正常工作,代码仍然可以正常编译,但它在执行时开始崩溃。
通过 ddd 调试显示,当我的 main 函数调用 Bar() 时,它实际上是在 foo.C 中调用 Bar(),而不是我自己定义的 Bar()。
当然,修复是静态我自己的函数或更改我自己的 Bar() 函数的名称。

我知道编写这样的代码杂乱无章,并且容易出现这样的错误。有人可以向我解释为什么代码会不一致地崩溃吗?

谢谢你们

问候

4

2 回答 2

2

内联函数仍然有外部链接。也就是说,它们由编译器发出到相应的目标文件中,当链接器链接应用程序时,它认为所有具有相同签名(包括它们的名称和封闭命名空间)的函数都是相同的。由于定义了该函数,inline它随机选择其中一个定义并删除另一个定义,而不会出错。(这违反了单一定义规则,根据标准导致未定义的行为。)

为防止出现此问题,请使用匿名命名空间,如下所示:

namespace {
inline int Bar(const int &a)  
{  
...  
}  
}

在您的情况下,在 foo.C 或 main 中这样做就可以了。等效地,您可以添加static

static int Bar() {}

如果你用 C 语言编写。

使用匿名命名空间或static关键字使函数成为翻译单元的本地函数,因此链接器不会将其视为外部符号。这样,您可以在不同的翻译单元中拥有具有相同签名的任意数量的函数。

于 2012-07-13T20:51:57.527 回答
0

我认为您正在使用 foo 定义的 Bar 函数,因为在您定义自己的 Bar 函数之前,它是通过 foo.h #included 的。

我很惊讶您的编译器没有警告您有关重复定义(非法),但是如果您在 #include "foo.h" 之前定义了 Bar 函数,则应该会引发错误。

这个 URL 说重新定义内联是非法的,除非内联是相同的:

C静态内联函数重定义规则

我的编译器对此抛出错误。最好的避免方法是使用单独的命名空间或宏保护。

于 2012-07-13T20:52:30.590 回答