2014-04-09 28 views
3

我已經爲嵌入式系統編寫了一些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 

Compil er/Linker輸出: 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大浦」 collect2.exe:錯誤:LD在返回退出狀態1

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

刪除該命名空間解決了這個問題,但爲什麼它編譯,鏈接,工作KEIL?任何人都可以向我解釋這個嗎?

+3

不要在頭文件中使用匿名命名空間 –

+0

無論如何在頭文件中使用無名命名空間有什麼好處? +1順便寫出一個寫得很好的問題。 – OMGtechy

+0

@OMGtechy:clambake的推理是「*匿名命名空間,因爲它們包含在整個項目中*」;但它是有缺陷的 - 匿名命名空間完全相反。 – Clifford

回答

0

我會建議這是濫用匿名命名空間功能。它與你想要達到的完全相反。

匿名名稱空間用於將定義本地化爲單個翻譯單元。如果您將頭文件放置在頭文件中,那麼將該頭文件包含在多個翻譯單元中,這將在您的代碼中產生多個獨立的定義。

這到底是怎麼發生的VC++是一個全球性的ourA已實例化爲一個指向A一個本地定義在main.cpp中定義,那麼晚些時候當地定義不再是可見的,但是從當前可見的不同本地版本在notmain.cpp中。 ZN8sunshine4InitEv這個名稱區分了獨立的定義,但名稱修改是由編譯器定義的,我猜ARM的RealView編譯器(由uVision使用)具有不同的方案,無法發現此錯誤。

事實上並不清楚這個錯誤在RealView中的結果是什麼,但它不可能是正確的,或者至少沒有明確的定義。

RealView實際上在發佈其他編譯器正常執行的警告時實在相當差,並且在發現未定義的行爲時有點寬鬆。使用另一個工具鏈(如MinGW/GCC和-Werror -Wall)或使用靜態分析工具來清理代碼總是值得的。

要解決此問題,您應該使用明確命名的命名空間,或者根本不使用命名空間。

+0

這裏的匿名命名空間或多或少是我前一段時間不同功能的人工產物。無論如何,這個階段不需要。我必須同意我的意思不完全符合。我將放棄命名空間。 – clambake

+0

您可以將匿名命名空間視爲「靜態」鏈接說明符(而不是「靜態」存儲類)的替代品。在C++中,作爲鏈接說明符的'static'關鍵字被棄用,以支持匿名名稱空間。 – Clifford