我为嵌入式系统编写了一些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 to
ourA'中
collect2.exe:错误:ld返回1退出状态
09:09:57 Build Finished (took 702ms)
删除该命名空间可以解决问题,但为什么要编译,链接,在KEIL中工作?任何人都可以向我解释这个吗?
答案 0 :(得分:0)
我建议这是滥用匿名命名空间功能。它与你想要实现的完全相反。
匿名命名空间用于将定义本地化为单个翻译单元。如果将一个放在头文件中,则将该头包含在多个转换单元中,这将导致代码中出现多个独立定义。
这里发生的事情VC ++是一个全局ourA
已被实例化为指向main.cpp中定义的A
的一个本地定义的指针,然后是 local 定义不再可见,但与notmain.cpp中当前可见的本地版本不同。名称重整ZN8sunshine4InitEv
区分独立定义,但名称重整是编译器定义的,我猜ARM的RealView编译器(由uVision使用)有一个不同的方案,无法发现此错误。
实际上不清楚RealView中出现此错误的结果是什么,但它不能正确或至少定义得很好。
实际上,RealView在发出其他编译器正常发出的警告方面相当差,而且在我发现的未定义行为方面有点宽容。总是值得使用另一个工具链,例如MinGW / GCC和-Werror -Wall,或者使用静态分析工具来清理代码。要解决此问题,您应该使用显式命名的命名空间,或者根本不使用命名空间。