在sockaddr指针和sockaddr_in指针之间进行强制转换
casting between sockaddr pointer and sockaddr_in pointer
我偶然看到一个套接字编程教程,里面引用了
"指向结构体sockaddr_in的指针可以被强制转换为指向结构体sockaddr的指针,反之亦然"
我不明白sockaddr_in如何被强制转换为sockaddr。将大类型的指针强制转换为小类型会导致UD行为。
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
struct sockaddr_in {
short int sin_family; // Address family, AF_INET
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Same size as struct sockaddr
};
强制类型转换如何不被定义?把这些相互关联不是很不安全吗?
如果a类只有两个int型,B类有4个int型。如果我有一个B类型的指针,并将其转换为a类型,那么我肯定可以获取前两个元素。但是,如果类A首先声明了2个字符,然后声明了2个int型,那么指针将无法正确获取值,因为在这种情况下对象布局将是不同的。
编辑1:
class Anu
{
public:
char a;
int b;
Anu()
{
a='a';
}
};
class Anurag
{
public:
Anurag() { a=4;}
int a;
int b;
int c;
int d;
};
int main()
{
Anu objanu;
Anurag objanurag;
Anurag *ptrAnurag= &objanurag;
ptrAnurag= (Anurag*)&objanu;
cout<<ptrAnurag->a; //Some weird value here
return 0;
}
假设我改变了这个例子,这样两个类通过调整变量类型有相同的大小…对象的布局可能会有所不同,即使大小保持不变。
我要补充@gsamaras的回答,未定义行为并不总是意味着不好的事情即将发生。未定义行为实际上是说"如果XYZ发生,我们*不提供任何关于接下来应该发生什么的规范"。
(* c++标准).
这是操作系统发生的地方,并说"它是由我们定义的"。
虽然转换不相关的结构(sockaddr_in
, sockaddr
)可能是标准未定义的行为,但操作系统API指定它与他们的API有效。
大小不同不重要。就像你可以将不同长度的字符串传递给不同的字符串处理函数一样,你也可以将不同长度的struct sockaddr
传递给不同的套接字处理函数。
struct sockaddr
的大小由被调用函数根据结构体sa_family
成员的内容来解释。还要注意,所有接受struct sockaddr *
地址的函数也接受socklen_t
参数,该参数保存传递的结构体的大小。
例如,struct sockaddr_un
结构是110字节:
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};
被调用的函数如bind()
或getpeername()
的声明类似于
int getpeerame(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
,因为不同套接字结构的大小不同。
注意struct sockaddr_???
的第一个成员是sa_family
。因此它总是在同一个地方
它们的大小相等,所以不,你没有得到任何UB!
证明:
#include <stdio.h>
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
// src: http://www.gta.ufrj.br/ensino/eel878/sockets/sockaddr_inman.html
struct in_addr {
unsigned long s_addr; // load with inet_aton()
};
struct sockaddr_in {
short int sin_family; // Address family, AF_INET
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Same size as struct sockaddr
};
int main (void) {
printf("%zun", sizeof(unsigned short) + sizeof(char) * 14);
printf("%zun", sizeof(short int) + sizeof(unsigned short int) + sizeof(struct in_addr) + sizeof(unsigned char) * 8);
return 0;
}
输出:16
16
好评论:sockaddr: 2+14=16, sockaddr_in:2+2+4+8=16 - Amer Agovic
您可能还想看一下这个问题:为什么结构体的n't sizeof等于每个成员的sizeof之和?
请检查这个问题:是否有可能将结构强制转换为另一个?
我在这里也复制了Benoit的答案:
这被称为类型双关语。这里,两个结构具有相同的大小,因此不存在结构大小的问题。虽然你几乎可以将任何东西强制转换成任何东西,但是用结构体来做是很容易出错的。
和Richard J. Ross III的这首
这是C语言的"继承"形式。(注意引号)。这是有效的,因为C并不关心地址中的底层数据,只关心您表示它的方式。
函数通过使用sa_family字段来确定它实际是什么结构,并将其强制转换为函数内部适当的sockaddr_in。
- 1d 智能指针不适用于语法 (*)++
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 为什么使用 "this" 指针调用派生成员函数?
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用指针从C++中的数组中获取最大值
- 助记符和指向成员语法的指针
- 嵌入方指针压缩已禁用
- 数组的指针从不分段故障
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- 何时在引用或唯一指针上使用移动语义
- QMetaObject invokeMethod的基于函数指针的语法
- 如何从 std::atomic 中提取指针 T<T>?
- 如何在 C# 中映射双 C 结构指针?
- C++将浮点指针值舍入为小数位数
- 为什么++(*p)更改指针值
- 调整大小后指向元素值的指针unordered_map有效?
- 正在将指针转换为范围
- 使用指向成员的指针将成员函数作为参数传递
- gdb:打印sockaddr指针值
- 在sockaddr指针和sockaddr_in指针之间进行强制转换