winsock編程:關於因爲頭文件而報錯的問題

關於頭文件#include<windows.h>放在#include<winsock.h>之前報錯的問題。初學者或者沒有耐心者可以忽略本小節的筆記。

例如源文件1中:

#include<windows.h>
#include<winsock2.h>
//...
//...

或者例如源文件2中:

#include<winsock.h>
#include<winsock2.h>
//...
//...

編譯這兩個源文件時,編譯出錯的內容如下:

definition of 'FD_SET'
...\winsock2.h(143) : error C2011: 'timeval' : 'struct' type redefinition
...\include\winsock2.h(199) : error C2011: 'hostent' : 'struct' type redefinition
...\winsock2.h(212) : error C2011: 'netent' : 'struct' type redefinition
........

報錯的意思是所有與這兩個頭文件包含和socket接口有關的函數以及結構體等都提示這樣的錯誤:redefinition(函數以及結構體等類型重複定義)。

報錯的原因

在源文件1報錯的原因:

windows.h包含了winsock.h和winsock2.h(在老版本windows系統編譯下只包含winsock.h頭文件)。由於winsock.h和winsock2.h這兩個頭文件是不能共存的,因爲這兩個頭文件都存在一些相同的某變量或者函數定義名稱,在執行代碼中創建了對象(該對象都屬於winsock.h和winsock2.h的),利用該對象進行訪問這兩個頭文件裏面的信息,一旦出現一些變量的名稱都相同,進而導致這些變量重複定義的錯誤。

在源文件2報錯的原因:

像源文件1報錯的原因一樣,由於winsock.h和winsock2.h是不能共存的,所以導致了重複定義的錯誤。

那麼問題來了,爲什麼如下代碼,卻不會報錯呢。

在源文件1中修改代碼爲:

#include<winsock2.h>
#include<windows.h>
//......

在源文件2中修改代碼爲:

#include<winsock2.h>
#include<winsock.h>
//....

爲什麼把winsock2.h放在winsock.h或者包含winsock的windows.h的前面,再編譯這兩個文件就不會出錯呢?

 先放着這個問題在一邊暫時不思考,然後講一下winsock.h和winsock2.h的主要區別。

相同點:

1.winsock.h和winsock2.h都包含在同一個目錄(如果在VC6.0環境下,包括windows.h,它們都在“...\Microsoft Visual Studio\VC98\Include”的文件夾裏面)。

區別:

1.版本區別,winsock.h版本爲1.1,而winsock2.h版本爲2.0.

2.winsock2是winsock的升級版,winsock2對於對於winsock來說是向下兼容的,由於因爲兼容,winsock有的東西,winsock2都有。

3.winsock支持的協議比winsock要多。

4.winsock2引用了新的SPI接口。主要意義是爲了打破提供者的透明,開發者可以自己編寫SPI接口。

5.winsock2擴展了更多與winsock所沒有的功能,比如說,擴展TCP/IP協議棧,URL以及網絡安全控制等。

好了,理解了它們之間的關係,讓我們返回來看看那個不會報錯的問題。

winsock2.h文件的部分內容

#ifndef _WINSOCK2API_
#define _WINSOCK2API_
#define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
//...
//...
#endif
說明:在winsock.h頭文件提前定義winscok.h的目的是阻止windows.h文件裏面#include<winsock.h>的定義以及在winsock.h文件的定義

winsock.h文件的部分內容

說明:進行宏定義WINSOCKAPI_,也就是引用winsock1.1版本

#ifndef _WINSOCKAPI_
#define _WINSOCKAPI_

windows.h文件部分內容

#if(_WIN32_WINNT >= 0x0400)/
#include <winsock2.h>
#include <mswsock.h>
#else
#include <winsock.h>
#endif /* _WIN32_WINNT >=  0x0400 */

說明:由於在VC6.0環境下,該條件不滿足,所以只引用了winsock.h。然而在VS環境下查看不到有這部分內容,不過編譯時默認引用了winsock.h,也許Visual Studio開發團隊對其進行優化了吧。至於_WIN32_WINNT是什麼,我不再深究講述下去,在這裏討論沒意義,有興趣者自行研究。

沒有報錯的主要原因:

由於windows.h裏面包含了winsock1.1和winsock2.0這兩個版本,但是windows編譯的通常情況下是選擇了winsock.h。首先引用了#include<winsock2.h>,由於winsock2.h頭文件裏“#define _WINSOCKAPI_  ”預定義了宏,如果系統再指向下一步#include<winsock.h>(或者#include<windows.h>),由於#ifdef語句判斷了winsock在winsock2.h文件早就定義過,所以就不會重複再定義這個了。

如果說,引用winsock.h再在引用winsock2.h的話,winsock在其文件早就定義了,在winsock2.h當中,#ifdef判斷的是winsock2.0有沒有定義,顯然是滿足條件的,所以在定義winscok2.0宏的同時就會重複定義wiinsock1.1。所以,如果winsock2.h預先被引用的話,下一個winsock.h就不會被用到,這就是所謂的兩者不能共存。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章