Amumu
Amumu

Reputation: 18552

Casting from bigger datatype (struct) to smaller one

I already knew pointer of a struct can be cast to another pointer of a struct with equivalent memory layout.

However, in the following piece of code:

#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 is cast to (struct sockaddr *)&their_addr. The layout of each struct is:

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

and:

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 is definitely a bigger information storage, so it can be cast to whatever smaller than it to fit a function declaration. Inside the function, it does not matter what type of struct is, as long as the passed struct into the function has enough memory blocks for the function to operate as the required struct. Is this correct?

Upvotes: 2

Views: 1251

Answers (1)

littleadv
littleadv

Reputation: 20272

Yes, it is correct. Basically, its similar to converting a derived class pointer to a base class pointer (and that's how it is implemented in C, in fact).

The content of the 14 bytes will be set based on the value of the ss_family, and then you can convert it to one of the specific structs.

Upvotes: 3

Related Questions