getnameinfo specifies socklen_t

2020-03-05 02:49发布

问题:

The 2nd arg for the getnameinfo prototype asks for a socklen_t type but sizeof uses size_t. So how can I get socklen_t ?

Prototype:

int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
       char *restrict node, socklen_t nodelen, char *restrict service,
       socklen_t servicelen, int flags);

Example:

struct sockaddr_in SIN;
memset(&SIN, 0, sizeof(SIN)); // This should also be socklen_t ?
SIN.sin_family      = AF_INET;
SIN.sin_addr.s_addr = inet_addr(IP);
SIN.sin_port        = 0;

getnameinfo((struct sockaddr *)&SIN, sizeof(SIN) /* socklen_t */, BUFFER, NI_MAXHOST, NULL, 0, 0);

This will give compiler error:

socklen_t VAR;
getnameinfo((struct sockaddr *)&SIN, &VAR, BUFFER, NI_MAXHOST, NULL, 0, 0);

回答1:

size_t is defined as an unsigned integral type; C99 guarantees that it is at least 16 bits.

socklen_t is defined as an integral type of at least 32 bits. (Edit: It's not necessarily unsigned, although in practice a negative length would be meaningless.)

So there's no problem with passing a size_t parameter and letting the compiler implicitly cast it to socklen_t, and I would argue that it makes your code clearer to let the implicit conversion occur instead of adding pedantic casts.

Your final example

socklen_t VAR;
getnameinfo((struct sockaddr *)&SIN, &VAR, BUFFER, NI_MAXHOST, NULL, 0, 0);

gives a compiler error because you're passing a pointer-to-a-socken_t instead of a socklen_t.



回答2:

Your information are out of date, socklen_t is an integer type (not necesarily unsigned) of at least 32 bits (http://www.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html).



回答3:

(This is rather an answer to this IMHO falsely duplicate-tagged question that tries to get to the bottom of socklen_t's existence.)

As others have pointed out it can be thought of as the size_t equivalent of the POSIX Sockets API that represents the length of various data structures in bytes. It is most notable in the bind(), listen(), connect() functions where it denotes the length of the various implementations of struct sockaddr but it is not limited to that at all.

The POSIX specification actually explains how it became to be and is very instructive IMHO:

The type socklen_t was invented to cover the range of implementations seen in the field. The intent of socklen_t is to be the type for all lengths that are naturally bounded in size; that is, that they are the length of a buffer which cannot sensibly become of massive size: network addresses, host names, string representations of these, ancillary data, control messages, and socket options are examples. Truly boundless sizes are represented by size_t as in read(), write(), and so on.

All socklen_t types were originally (in BSD UNIX) of type int. During the development of POSIX.1-2008, it was decided to change all buffer lengths to size_t, which appears at face value to make sense. When dual mode 32/64-bit systems came along, this choice unnecessarily complicated system interfaces because size_t (with long) was a different size under ILP32 and LP64 models. Reverting to int would have happened except that some implementations had already shipped 64-bit-only interfaces. The compromise was a type which could be defined to be any size by the implementation: socklen_t.