首先回顾一下typedef的用法:
typedef char A,*B;
cout<<sizeof(A)<<endl; //1
cout<<sizeof(B)<<endl; //4,64位机子,地址指针按照机器运算而不是win32预编译定义。
typedef不是#define宏那样做字符替换,而是声明类型别名,具有最高仅次于预编译的优先级,高于算数运算符和其他操作符,const B pc。pc是常量指针,指向char类型。
初看到这段代码时,一直在纠结MAKEWORD的用法,源码如下:
#define MAKEWORD(a, b) ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
一个宏定义。
typedef unsigned short WORD;
WORD 是用unsigned short定义的,一般23位机器为2字节,即16bit;而我的机器是64位,但是用的是win32的编译器,结果
cout<<sizeof(unsigned short)<<endl; //-------------------------------2字节。
cout<<sizeof(ULONG_PTR)<<endl; //-------------------------------4字节。
cout<<sizeof(unsigned long)<<endl; //-------------------------------4字节。
BYTE 8bit 。
值得玩味是的DWORD_PTR:
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
到底__W64 unsigned long 是怎么回事,至少大家没用过这个类型吧。实际这是编译器相关的代码了,由于socket本身要求跨机器传输数据,所以我们必须认真了解按照相同标准去实现在不同编译器上的源码原理,再深入下去则要进入计算机实现原理和编译原理的范畴了,暂时没能力去深吃这些知识,但是我们可以瞄了一下相关的宏定义:
#if defined(_WIN64)
typedef __int64 INT_PTR, *PINT_PTR;
typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
typedef __int64 LONG_PTR, *PLONG_PTR;
typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
#define __int3264 __int64
#else
typedef _W64 int INT_PTR, *PINT_PTR;
typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;
typedef _W64 long LONG_PTR, *PLONG_PTR;
typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
#define __int3264 __int32
#endif
实际上我们可以认为:win32模式下,
_W64 unsigned <span style="font-family: Arial, Helvetica, sans-serif;">int</span>
就是我们我们在32位机器下使用的unsigned int,__64是编译器内部基于不同长度机器编译的识别码。通过_W64前缀,最后在64位机器上完成32位程序的编译。
基于此,我们可以知道MAKEWORD其实是将(低位a,高位b),链接成一个16位即2字节的unsigned short int。(win32模式)。
以为socket传输最后的单位就是位,所以我们要明确控制数据的长度。
同时,我们可以看到winSocket2为了支持32位和64位机器通信,定义的数据结构(具体是不是从BSD标准来的,暂时我们不去关注)
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
#ifdef _WIN64
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
#else
char szDesc