淺談__declspec(selectany)該何時用

淺談__declspec(selectany)該何時用

__declspec是一個Microsoft Visual C++特定的編譯器屬性開關。括號中指
明的是哪一個屬性生效。關於
__declspec的其他屬性可以百度“__declspec msdn”

查看微軟的官方幫助。也可以參看博客中轉載的文章。

言歸正傳。__declspec(selectany)在MSDN中的說明是這樣的:

Tells the compiler that the declared global data item (variable or object) is a pick-any 

COMDAT (a packaged function). At link time, if multiple definitions of COMDAT are 

seen, the linker picks one and discards the rest. Selectany can be used in initializing 

global data defined by headers,when the same header appears in more than one 

source file. 


簡單翻譯一下:告訴編譯器定義的全局數據項(變量或對象)這是一套能被任

意挑選的COMDAT(一套函數)。在鏈接時,如果多個COMDAT的定義被找到,

鏈接器將挑選一個並剔除其他的多餘的。Selectany可以被用於當定義有初始化全局

變量數據的頭文件被應用於多於一個的源文件時。

我這樣的翻譯還是挺虛的,直白了說:當在頭文件定義全局變量,並且這個頭

文件被include多次時可以用這個開關剔除由於多次include而產生的重定義。

看起來這個開關很有用,但這個開關我們用得並不多。很明顯,根據msdn的解釋,

對於定義常量這個開關是用不上的了,而全局變量一般來說定義在cpp中,那麼這個

開關有什麼用呢?


這正是這篇文章要討論的主題。

(1)基於程序結構的整齊,統一將全局變量定義在一個全部cpp都引用的頭文件,

這樣也就避免了在每個cpp中用extren導入外部變量。當然,這隨你的習慣了。

(2)模板的設計。類模板,函數模板,這些肯定不會只被一個cpp所使用,按照一般

的習慣都是寫在頭文件的。但是對於模板,其實現是在編譯期完成的,那就要求必須

在編譯的時候同時找到模板的定義和實現,也就是意味着不可能像以前的習慣一樣,

將類的聲明放在頭文件,將實現放在cpp中。那麼模板類的靜態成員變量怎麼辦呢?

類的靜態成員必須在類外部初始化,如果是全寫在頭文件,當頭文件include多於一次

的時候就會出現類的靜態變量重定義的問題,可以做一個簡單的實驗:

sy.h:

class A
{
public:
	static int u;
};
int A::u=1;

1.cpp:

#include"sy.h"

int main()
{
	return 0;
}

2.cpp:

#include"sy.h"

就這樣三個文件,在一個工程中,組建一下(編譯沒問題,問題出在鏈接的時

候),就會出現:

2.obj : error LNK2005: "public: static int A::u" (?u@A@@2HA) already defined in sy.obj
Debug/sy.exe : fatal error LNK1169: one or more multiply defined symbols found

這時候就只能使用__declspec(selectany)去解決了,將sy.h的第六行改爲:

__declspec(selectany) int A::u=1;

即可解決問題。


下面來討論一個問題,那麼看下面的代碼:

key.h:

<span style="font-size:18px;">const char *Function[28]=
{
	"menu","exit","rad",
	"sin","cos","tan",
	"sec","csc","cot",
	"asin","acos","atan",
	"acsc","asec","acot",
	"sh","ch","th","ash",
	"ach","ath","log",
	"lg","ln","sum",
	"mul","A","C"
};</span>

這個頭文件被include了多次。我的原意的是希望建立一個字符串的數

組常量,上面說了定義常量並不需要用這個開關,但爲什麼還是會出

現重定義的問題呢?而且確實能用__declspec(selectany)去解決。


實際上這個可以不用__declspec(selectany)去解決,寫成這樣即可:

<span style="font-size:18px;">const char* const Function[28]=
{
	"menu","exit","rad",
	"sin","cos","tan",
	"sec","csc","cot",
	"asin","acos","atan",
	"acsc","asec","acot",
	"sh","ch","th","ash",
	"ach","ath","log",
	"lg","ln","sum",
	"mul","A","C"
};</span>

如果在看了我的原意之後並沒有發現一開始給的代碼有什麼問題,請想

一下__declspec(selectany)去解決雖然沒有問題,但符合我的原意嗎?

這樣Function的內容到底是變量還是常量?

發佈了47 篇原創文章 · 獲贊 178 · 訪問量 56萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章