簡體   English   中英

在sockaddr和sockaddr_in之間進行轉換

[英]casting between sockaddr and sockaddr_in

我遇到了一個套接字編程教程,引用它

“指向struct sockaddr_in的指針可以轉換為指向struct sockaddr的指針, 反之亦然

我不明白如何將sockaddr_in投射到sockaddr。 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
};

演員如何不被定義? 把它們互相投射不是不安全嗎?

如果我有A級只有兩個整數而B級有4個整數。 如果我有一個類型B的指針,我將其轉換為A類型,那么我確定我可以獲取前兩個元素。 但是,如果類A首先聲明了2個字符並且稍后聲明了2個字符,則指針將無法正確獲取值,因為在這種情況下對象布局將是不同的。

編輯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不相關的結構( sockaddr_insockaddr )可能是未定義的行為,但OS API指定它對其API有效。

它們的大小相同 ,所以不,你沒有任何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("%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;
}

輸出:

16
16

好評:sockaddr:2 + 14 = 16,sockaddr_in:2 + 2 + 4 + 8 = 16 - Amer Agovic

您可能還想看看這個問題: 為什么結構的sizeof不等於每個成員的sizeof之和?


請檢查這個問題: 是否可以將結構轉換為另一個?

我也在這里復制Benoit的答案:

這被稱為Punning類型 這里,兩個結構都具有相同的大小,因此不存在結構大小的問題。 雖然你幾乎可以將任何東西投射到任何東西上,但使用結構進行渲染很容易出錯。

還有Richard J. Ross III的這個:

這是C的“繼承”形式(注意引號)。 這是有效的,因為C不關心地址中的基礎數據,只是你所代表的。

該函數通過使用sa_family字段確定它實際上是什么結構,並將其強制轉換為函數內部的正確sockaddr_in。

不同的尺寸無關緊要。 就像您可以將不同長度的字符串傳遞給各種字符串處理函數一樣,您可以將不同長度的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_???的第一個成員struct sockaddr_??? sa_family 因此,它總是在同一個地方。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM