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就不会被用到,这就是所谓的两者不能共存。


猜你喜欢

转载自blog.csdn.net/chen1083376511/article/details/80784207