vengy
vengy

Reputation: 2259

How to initialize a sockaddr_in struct with a single line of code?

Using a C89/C99 compiler, these two lines of code work

struct sockaddr_in server = { AF_INET, htons(27015), INADDR_ANY};
server.sin_addr.s_addr = inet_addr("127.0.0.1");

Is there a shorter version? For example, these do not work:

struct sockaddr_in server = { AF_INET, htons(27015), INADDR_ANY, inet_addr("127.0.0.1")};
struct sockaddr_in server = { AF_INET, htons(27015), INADDR_ANY, .sin_addr.s_addr = inet_addr("127.0.0.1") };

This unsightly long version works fine

struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(27015);
server.sin_addr.s_addr = INADDR_ANY;
server.sin_addr.s_addr = inet_addr("127.0.0.1");

The sockaddr_in has this format:

typedef struct sockaddr_in {
    short   sin_family;
    USHORT  sin_port;
    IN_ADDR sin_addr;
    CHAR    sin_zero[8];
} SOCKADDR_IN, *PSOCKADDR_IN;

Windows Client

https://godbolt.org/z/8q8GPxP54

Windows Server

https://godbolt.org/z/8j3ozKKxP

This suggested code does not connect

struct sockaddr_in server = { AF_INET, htons(27015), {inet_addr("127.0.0.1")}, {0} };

This code does connect

struct sockaddr_in serverX;
serverX.sin_family = AF_INET;
serverX.sin_addr.s_addr = INADDR_ANY;
serverX.sin_port = htons(27015);
serverX.sin_addr.s_addr = inet_addr("127.0.0.1");

Here's the difference between the versions. Notice, s_addr in server struct is 0x0000007f, whereas it's 0x0100007f in serverX:

trace

Upvotes: 0

Views: 2068

Answers (1)

dbush
dbush

Reputation: 223689

Two things: first, you've got the initalizer for sin_addr in the wrong place. It's the third element in the struct, so the initializer should be third. Second, since sin_addr is a struct type, you need to put its initializer in braces as well.

So what you want is:

struct sockaddr_in server={ AF_INET, htons(27015), {inet_addr("127.0.0.1")}, {0}};

As was mentioned in the comments however, condensing code onto one line usually isn't good practice because it can make code harder to read. Personally I'd prefer the long version as it makes it more clear to the reader which fields are being initialized with what.

Also note that this will only work on systems where the .s_addr field is defined as a macro, as many systems do. For example, Windows (which you appear to be using) defines struct in_addr as follows:

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;
#define s_addr  S_un.S_addr
                                /* can be used for most tcp & ip code */
#define s_host  S_un.S_un_b.s_b2
                                /* host on imp */
#define s_net   S_un.S_un_b.s_b1
                                /* network */
#define s_imp   S_un.S_un_w.s_w2
                                /* imp */
#define s_impno S_un.S_un_b.s_b4
                                /* imp # */
#define s_lh    S_un.S_un_b.s_b3
                                /* logical host */
};

As do many older UNIX distributions.

So to reiterate, use the code that's the most clear to the reader, not what fits on one line.

Upvotes: 1

Related Questions