[英]casting between sockaddr and sockaddr_in
I came across a socket programming tutorial in which it is quoted 我遇到了一个套接字编程教程,引用它
"a pointer to a struct sockaddr_in can be cast to a pointer to a struct sockaddr and vice-versa "
“指向struct sockaddr_in的指针可以转换为指向struct sockaddr的指针, 反之亦然 ”
I dont understand how can sockaddr_in be cast to sockaddr. 我不明白如何将sockaddr_in投射到sockaddr。 Casting a pointer of Big type to Small type should give UD behavior.
将Big类型的指针强制转换为Small类型应该给出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
};
How can the cast not be undefined? 演员如何不被定义? Isn't it unsafe to cast these to each other?
把它们互相投射不是不安全吗?
If i have a class A having only two ints and class B having 4 ints. 如果我有A级只有两个整数而B级有4个整数。 And if i have a pointer of type B and i cast it to type A then sure i can fetch the first two elements.
如果我有一个类型B的指针,我将其转换为A类型,那么我确定我可以获取前两个元素。 But if class A has 2 chars declared first and 2 ints declared later then the pointers would not right fetch the values since the object layout in this case would be different.
但是,如果类A首先声明了2个字符并且稍后声明了2个字符,则指针将无法正确获取值,因为在这种情况下对象布局将是不同的。
Edit 1: 编辑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;
}
Assuming i change the example so that both classes have same size by adjusting the variables types...still the object layout might be different even though the size remains the same. 假设我通过调整变量类型来更改示例以使两个类具有相同的大小...即使大小保持不变,对象布局仍然可能不同。
I'll add to @gsamaras answer by saying that Undefined Behaviour doesn't always means that bad things are about to happen. 我将添加到@gsamaras的答案中说,未定义的行为并不总是意味着坏事即将发生。 Undefined Behaviour actually says "we* don't provide any specifications on what should happen next if XYZ occurs".
未定义的行为实际上表示“我们*不提供任何关于XYZ发生时应该发生什么的规范”。
(*the C++ standard). (* C ++标准)。
this is the place where the OS takes place and say "it is defined by us". 这是操作系统发生的地方,并说“它是由我们定义的”。
although casting unrelated structs ( sockaddr_in
, sockaddr
) may be undefined behaviour by the standard, the OS API specify that it is valid with their API. 尽管通过标准
sockaddr
不相关的结构( sockaddr_in
, sockaddr
)可能是未定义的行为,但OS API指定它对其API有效。
They are of equal size , so no, you don't get any UB ! 它们的大小相同 ,所以不,你没有任何UB !
Proof: 证明:
#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("%zu\n", sizeof(unsigned short) + sizeof(char) * 14);
printf("%zu\n", sizeof(short int) + sizeof(unsigned short int) + sizeof(struct in_addr) + sizeof(unsigned char) * 8);
return 0;
}
Output: 输出:
16
16
A good comment: sockaddr: 2+14=16, sockaddr_in:2+2+4+8=16 – Amer Agovic 好评:sockaddr:2 + 14 = 16,sockaddr_in:2 + 2 + 4 + 8 = 16 - Amer Agovic
You may also want to take a look at this question: Why isn't sizeof for a struct equal to the sum of sizeof of each member? 您可能还想看看这个问题: 为什么结构的sizeof不等于每个成员的sizeof之和?
Please, check this question: Is it possible to cast struct to another? 请检查这个问题: 是否可以将结构转换为另一个?
I am copying the answer of Benoit here too: 我也在这里复制Benoit的答案:
This is refered as Type Punning .
这被称为Punning类型 。 Here, both structures have the same size, so there is no question of struct size.
这里,两个结构都具有相同的大小,因此不存在结构大小的问题。 Although you can cast almost anything to anything, doing it with structures is error-prone.
虽然你几乎可以将任何东西投射到任何东西上,但使用结构进行渲染很容易出错。
and this one by Richard J. Ross III too: 还有Richard J. Ross III的这个:
This is C's form of "inheritance" (notice the quotes).
这是C的“继承”形式(注意引号)。 This works because C does not care about the underlying data in an address, just what you represent it as.
这是有效的,因为C不关心地址中的基础数据,只是你所代表的。
The function determines what structure it actually is by using the sa_family field, and casting it into the proper sockaddr_in inside the function.
该函数通过使用sa_family字段确定它实际上是什么结构,并将其强制转换为函数内部的正确sockaddr_in。
The different sizes don't matter. 不同的尺寸无关紧要。 Just like you can pass strings of different lengths to the various string-handling functions, you can pass
struct sockaddr
of different lengths to the various socket-handling functions. 就像您可以将不同长度的字符串传递给各种字符串处理函数一样,您可以将不同长度的
struct sockaddr
传递给各种套接字处理函数。
The size of the struct sockaddr
is interpreted by the called function per the contents of the sa_family
member of the structure. struct sockaddr
的大小由被调用函数根据结构的sa_family
成员的内容进行解释。 Note also that all functions that take a struct sockaddr *
address also take a socklen_t
argument that holds the size of the structure being passed. 另请注意,采用
struct sockaddr *
地址的所有函数也采用socklen_t
参数来保存传递的结构的大小。
For example, the struct sockaddr_un
structure is 110 bytes: 例如,
struct sockaddr_un
结构是110字节:
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};
The called function such as bind()
or getpeername()
have declarations similar to 被调用的函数(如
bind()
或getpeername()
具有类似的声明
int getpeerame(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
for the very reason that the size(s) of various socket structures vary. 由于各种插座结构的尺寸变化的原因。
Note that the first member of every struct sockaddr_???
注意每个
struct sockaddr_???
的第一个成员struct sockaddr_???
is the sa_family
. 是
sa_family
。 Thus it's always in the same place. 因此,它总是在同一个地方。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.