2011-12-05 43 views
2

構造体のポインタが同等のメモリレイアウトを持つ構造体の別のポインタにキャストできることはすでに知っていました。大きいデータ型(構造体)から小さなものへのキャスト

しかし、次のコードで:

#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

#define MYPORT "3490" // the port users will be connecting to 
#define BACKLOG 10  // how many pending connections queue will hold 

int main(void) 
{ 
    struct sockaddr_storage their_addr; 
    socklen_t addr_size; 
    struct addrinfo hints, *res; 
    int sockfd, new_fd; 

    // !! don't forget your error checking for these calls !! 

    // first, load up address structs with getaddrinfo(): 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE;  // fill in my IP for me 

    getaddrinfo(NULL, MYPORT, &hints, &res); 

    // make a socket, bind it, and listen on it: 

    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 
    bind(sockfd, res->ai_addr, res->ai_addrlen); 
    listen(sockfd, BACKLOG); 

    // now accept an incoming connection: 

    addr_size = sizeof their_addr; 
    new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size); 

    // ready to communicate on socket descriptor new_fd! 
    . 
    . 
    . 

struct sockaddr_storage their_addr(struct sockaddr *)&their_addrにキャストされます。各構造体のレイアウトは次のとおりです。

struct sockaddr { 
    unsigned short sa_family; // address family, AF_xxx 
    char    sa_data[14]; // 14 bytes of protocol address 
}; 

と:

struct sockaddr_storage { 
    sa_family_t ss_family;  // address family 

    // all this is padding, implementation specific, ignore it: 
    char  __ss_pad1[_SS_PAD1SIZE]; 
    int64_t __ss_align; 
    char  __ss_pad2[_SS_PAD2SIZE]; 
}; 

socktaddr_storageは間違いなく大きな情報記憶なので、それは関数宣言に合わせてよりどんな小さなにキャストすることができます。関数の中で渡された構造体が必要な構造体として機能するのに十分なメモリブロックを持っている限り、構造体の型は重要ではありません。これは正しいです?

答えて

3

はい、正しいです。基本的には、派生クラスのポインタを基本クラスのポインタに変換するのと同じです(実際はC言語で実装されています)。

ss_familyの値に基づいて14バイトの内容が設定され、one of the specific structsに変換されます。

+0

これはC++でのキャストに適用できますか?C++にはすでに4種類のキャストがあります(Cキャストのラッパーにすぎません)。また、私はBeejガイドで私を得ました:) – Amumu

+0

これは普通の古いCのキャストで、Cのデータを持つC関数を呼び出すので、その罰金です。オブジェクトポインタと共に使用すると危険です。あなたが望むなら、Cキャストの代わりにここでC++のキャスト演算子を使うことができますが、そうではありません。 – littleadv

+0

'sa_family'が' AF_INET6'である場合にのみ、 'sa_data [14]'は 'sa_data [46]'でなければなりません。バッファが小さすぎると失敗します。 – rtischer8277

関連する問題