【问题标题】:Anonymous namespace causes undefined reference here - works there匿名命名空间在此处导致未定义的引用 - 在那里工作
【发布时间】:2014-05-22 05:41:45
【问题描述】:

我已经为嵌入式系统编写了一些 C++ 代码,它的工作原理就像一个魅力。当前任务是在 PC 上模拟此设备的行为。必须移植一些代码:对于第一次测试,我使用的是 mingw (g++),而嵌入式系统是 STM32 并使用 KEIL µVision 工具链。

我遇到了一个与函数行为无关的问题,而不是编译器特定的怪异问题。我在匿名命名空间中定义了 2 个类,因为它们包含在整个项目中。现在在嵌入式设备上编译和运行没有问题。 g++ 抱怨一个未定义的引用!

当我删除围绕类的匿名命名空间时,它会编译并运行!但为什么?下面是一些重现这种情况的示例代码: main.cpp:

#include "notmain.h"
#include "theclass.h"

A *ourA=NULL;

int main()
{
    theA = new A();
    theA->dostuff(1024);
    sunshine sun;
    sun.Init();
}

notmain.cpp:

#include "notmain.h"
#include "theclass.h"

void sunshine::Init()
{
    theA->dostuff(127);
}

notmain.h:

#ifndef NOTMAIN_H_
#define NOTMAIN_H_
class sunshine
{
public:
    void Init();
};
#endif

theclass.h:

#ifndef THECLASS_H_
#define THECLASS_H_
#include <stdio.h>
#define theA ourA
namespace
{
    class A
    {
    public:
        void dostuff(int b)
        {
            a = b;
            printf("Hello: %d\n",a);
        }
    private:
        int a;
    };
}
extern A *ourA;
#endif

编译器/链接器输出: 09:09:57 ** Testo项目配置调试的增量构建** 信息:内部构建器用于构建 g++ -O0 -g3 -Wall -c -fmessage-length=0 -o main.o "..\main.cpp" g++ -O0 -g3 -Wall -c -fmessage-length=0 -o notmain.o "..\notmain.cpp" g++ -o Testo.exe notmain.o main.o notmain.o:在函数ZN8sunshine4InitEv': D:\Projekte\Testo\Debug/../notmain.cpp:6: undefined reference toourA' collect2.exe:错误:ld 返回 1 个退出状态

09:09:57 Build Finished (took 702ms)

删除该命名空间可以解决问题,但为什么它可以在 KEIL 中编译、链接和工作?谁能给我解释一下?

【问题讨论】:

  • 不要在头文件中使用匿名命名空间
  • 在标头中使用未命名的命名空间有什么好处? +1 顺便提一个写得很好的问题。
  • @OMGtechy:clambake 的推理是“一个匿名命名空间,因为它们包含在整个项目中”;但它是有缺陷的——匿名命名空间正好相反。

标签: c++ gcc g++ embedded keil


【解决方案1】:

我认为这是对匿名命名空间特性的滥用。它与您试图实现的目标完全相反。

匿名命名空间用于将定义本地化到单个翻译单元。如果您将一个放在头文件中,然后将该头包含在多个翻译单元中,这将导致您的代码中有多个独立的定义。

这里发生的 VC++ 是全局 ourA 已被实例化为指向 main.cpp 中定义的 A 的一个本地定义的指针,然后该 local 定义不再可见,但与 notmain.cpp 中当前可见的本地版本不同。 ZN8sunshine4InitEv 的名称修饰区分独立定义,但名称修饰是编译器定义的,我猜 ARM 的 RealView 编译器(由 uVision 使用)具有不同的方案,无法发现此错误。

实际上不清楚如果这个错误出现在 RealView 中会产生什么结果,但它不能是正确的,或者至少不能很好地定义。

RealView 实际上在发出其他编译器通常会发出的警告方面相当差,并且在涉及我发现的未定义行为时有点宽容。使用带有 -Werror -Wall 的其他工具链(例如 MinGW/GCC)或使用静态分析工具清理代码总是值得的。

要解决这个问题,您应该使用显式命名的命名空间,或者根本不使用命名空间。

【讨论】:

  • 这里的匿名命名空间或多或少是我前段时间拥有的不同功能的产物。在这个阶段,无论如何都不需要。我必须同意我并不完全符合这个意思。我将删除命名空间。
  • 您可以将匿名命名空间视为static 链接说明符的替代品(与static 存储类相对)。在 C++ 中,static 关键字作为链接说明符已被弃用,取而代之的是匿名命名空间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-22
  • 1970-01-01
  • 1970-01-01
  • 2017-05-27
  • 2016-12-17
相关资源
最近更新 更多