64

My doubt is related to the following structure of sockets in UNIX :

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET, AF_INET6
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

Here the member sin_addr is of type struct in_addr.

But I don't get why someone would like to do that as all struct inaddr has is :

struct in_addr {
    unsigned long s_addr;          // load with inet_pton()
};

All in_addr has is just one member s_addr. Why cannot we have something like this :

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET, AF_INET6
    unsigned short   sin_port;     // e.g. htons(3490)
    unsigned long    s_addr ; 
    char             sin_zero[8];  // zero this if you want to
};
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Deepankar Bajpeyi
  • 5,661
  • 11
  • 44
  • 64
  • 1
    I'd even suggest you read [this](http://beej.us/guide/bgnet/output/html/multipage/sockaddr_inman.html) if you want to know more about the whole family! – cmc Dec 20 '12 at 19:56
  • 2
    This is a spot on question EVERYONE wonders once or more. The reasons boil down to the reasons to use structs (and even unions) in classical C real world usage, where specific use-cases or platform implementations may vary the detail but still marry the API. – uchuugaka Jan 20 '15 at 14:45
  • 2
    What is interesting is I haven't worked in this area for the past 2 years and I have quite forgotten why I asked this. Its still my most popular question and probably making a lot of people wonder and get deeper into the topic. Love how this community works. – Deepankar Bajpeyi Jan 20 '15 at 16:57
  • To allow versatility in the implementation. – Gabriel Staples Apr 12 '22 at 01:17

3 Answers3

35

struct in_addr is sometimes very different than that, depending on what system you're on. On Windows for example:

typedef struct in_addr {
  union {
    struct {
      u_char s_b1,s_b2,s_b3,s_b4;
    } S_un_b;
    struct {
      u_short s_w1,s_w2;
    } S_un_w;
    u_long S_addr;
  } S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

The only requirement is that it contain a member s_addr.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • 3
    More precisely, that `sin_addr.s_addr` result in a lvalue of a 32-bit integer type that represents the address. AFAIR I saw also things like `#define s_addr S_un.S_addr`. But this is something extremely stupid - or simply comes from times of really retarded C language which didn't support anonymous unions. – Ethouris Jul 31 '15 at 14:56
11

struct in_addr is a more than just an integer is because it might have more than in_addr_t. In many systems, it has a union, and the reason of such implementation is for class A/B/C addresses, which are not used now.

Unix Network Programming Volume 1 explains the historical reason in detail:

The reason the sin_addr member is a structure, and not just an in_addr_t, is historical. Earlier releases (4.2BSD) defined the in_addr structure as a union of various structures, to allow access to each of the 4 bytes and to both of the 16-bit values contained within the 32-bit IPv4 address. This was used with class A, B, and C addresses to fetch the appropriate bytes of the address. But with the advent of subnetting and then the disappearance of the various address classes with classless addressing, the need for the union disappeared. Most systems today have done away with the union and just define in_addr as a structure with a single in_addr_t member.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
8

Because the in_addr structure may contain more than one member.

http://pubs.opengroup.org/onlinepubs/009604599/basedefs/netinet/in.h.html

ouah
  • 142,963
  • 15
  • 272
  • 331
  • 3
    This basically answers everything there is to answer. The reason `struct in_addr` exists is because it *may* be more than just one integer. –  Dec 20 '12 at 19:31