简体   繁体   English

在sockaddr和sockaddr_in之间进行转换

[英]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_insockaddr )可能是未定义的行为,但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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM