问题
最近在写Ethernet通讯相关的代码时发现bind()和accept()这些函数接受的是sockaddr*,但是咱定义的结构体是sockaddr_in类型的,一般都是在传入参数的时候加上(struct sockaddr *)显示转换就可以了。但是为什么不同结构体类型的指针可以之间转换呢?
答案(大概吧)
sockaddr_in和sockaddr是并排结构,指向sockaddr_in结构的指针也可以指向sockraddr结构并替换。
可以看见两者的结构分别为(不同地方定义可能不一样):
struct sockaddr {
unsigned char sa_len;
unsigned char sa_family;
char sa_data[14];
};
struct in_addr {
unsigned long s_addr;
};
struct sockaddr_in
{
unsigned char sin_len;
unsigned char sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
可以看见两者的前面两项内容都是一样的。因此直接转换指针类型之后函数依然可以正确检索到前面重合的内容。
相关函数在实际操作过程中可以通过family项来判断整个结构体的实际长度,从而转换回正确的类型进行操作。
这也是为什么在使用这些函数的时候需要输入结构体的长度。假如函数转换得到的结构体长度与我们输入的长度不匹配,就报错了。