getnameinfo指定socklen_t

6

getnameinfo原型中的第二个参数要求使用socklen_t类型,但sizeof使用size_t。那么我该如何获得socklen_t?

原型:

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

例子:

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);

这将导致编译错误:

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

sizeof本身是否会引起问题? - Marcelo Cantos
1
你是否遇到了编译错误? - Daniel Stutzbach
没有问题或编译器错误,但我猜想如果getnameinfo要求socklen_t,那么我不应该传递size_t... - Neeladri Vishweswaran
1
人生中有更糟糕的事情需要担心。我从未见过关注此事的套接字代码。 - Marcelo Cantos
我总是按照原型要求提供服务。最佳实践。 - Neeladri Vishweswaran
3个回答

11

size_t 被定义为 一种无符号整型;C99保证其至少为16位。

socklen_t 被定义为 至少32位的整型。(编辑:它不一定是无符号的,虽然在实践中,负长度毫无意义。)

因此,将size_t参数传递并让编译器隐式地将其转换为socklen_t没有问题,我认为这样做会使您的代码更清晰,而不是添加冗长的强制转换。

您的最终示例

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

这个编译错误是因为你传递了一个指向socken_t的指针而不是socklen_t。


2
更重要的是,对于任何sockaddr类型的结构体,sizeof返回的值都可以适应于socklen_t类型,因此转换是安全的。 - caf

2

(这实际上是对这个我认为错误地重复标记的问题的回答,试图深入了解socklen_t的存在。)

正如其他人指出的那样,它可以被视为 POSIX Sockets API 的 size_t 等效物,表示以字节为单位的各种数据结构的长度。在 bind()listen()connect() 函数中最为显著,其中它表示各种 struct sockaddr 的实现的长度,但它并不仅限于此。

POSIX规范 实际上解释了它是如何产生的,并且非常有启发性,我认为:

类型socklen_t是为了覆盖现场中看到的各种实现而发明的。socklen_t的目的是成为所有长度的类型,这些长度在自然上限制在一定范围内,即它们是缓冲区的长度,这些缓冲区不可能变得非常大:网络地址、主机名、它们的字符串表示、辅助数据、控制消息和套接字选项都是例子。真正无限大小的长度则由size_t表示,例如read()、write()等函数。在BSD UNIX中,所有socklen_t类型最初都是int类型。在开发POSIX.1-2008期间,决定将所有缓冲区长度更改为size_t,这在表面上似乎是有道理的。当双模式32/64位系统出现时,这个选择使系统接口变得不必要地复杂,因为size_t(long)在ILP32和LP64模型下的大小不同。除了已经提供64位专用接口的一些实现之外,int可能会被还原回去。妥协方案是一种可以由实现定义为任何大小的类型:socklen_t。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接