【问题标题】:getnameinfo specifies socklen_tgetnameinfo 指定 socklen_t
【发布时间】:2010-05-04 12:15:03
【问题描述】:

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 本身是否会导致问题?
  • 您是否遇到编译错误?
  • 没有问题或编译器错误,但我猜如果 getnameinfo 要求 socklen_t 我不应该通过 size_t...
  • 生活中有更糟糕的事情需要担心。我从未见过对此感到困扰的套接字代码。
  • 我总是提供原型所要求的东西。最佳实践。

标签: c linux networking posix socklen-t


【解决方案1】:

size_tis defined 为无符号整数类型; C99 保证至少为 16 位。

socklen_t is defined 作为至少 32 位的整数类型。 (编辑:它不一定是无符号的,尽管实际上负长度是没有意义的。)

因此,传递 size_t 参数并让编译器将其隐式转换为 socklen_t 是没有问题的,我认为让隐式转换发生而不是添加迂腐转换可以使您的代码更清晰。

你的最后一个例子

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

给出编译器错误,因为您传递的是指向 a-socken_t 而不是 socklen_t 的指针。

【讨论】:

  • 更重要的是,sizeof 为任何sockaddr 类型结构返回的值将始终适合socklen_t 类型,因此转换是安全的。
【解决方案2】:

您的信息已过时,socklen_t 是至少 32 位 (http://www.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html) 的整数类型(不一定是无符号的)。

【讨论】:

    【解决方案3】:

    (这是对this IMHO falsely duplicate-tagged question 的一个回答,它试图了解socklen_t 的存在。)

    正如其他人所指出的,它可以被认为是 POSIX 套接字 API 的 size_t 等效项,它表示各种数据结构的长度(以字节为单位)。在bind()listen()connect() 函数中最值得注意的是,它表示struct sockaddr 的各种实现的长度,但根本不限于此。

    POSIX specification 实际上解释了它是如何形成的,并且非常有启发性,恕我直言:

    socklen_t 类型的发明是为了涵盖该领域中的各种实现。 socklen_t 的意图是成为所有长度自然有界的类型;也就是说,它们是缓冲区的长度,不能明智地变得庞大:网络地址、主机名、这些的字符串表示、辅助数据、控制消息和套接字选项都是示例。真正无限的大小由size_t 表示,如read()write() 等。

    所有socklen_t 类型最初(在BSD UNIX 中)都是int 类型。在 POSIX.1-2008 的开发过程中,决定将所有缓冲区长度更改为 size_t,这从表面上看是有意义的。当双模式 32/64 位系统出现时,这种选择不必要地使系统接口复杂化,因为size_t(带长)在 ILP32 和 LP64 模型下的大小不同。恢复到int 会发生,除非某些实现已经发布了仅 64 位的接口。妥协是一种可以由实现定义为任意大小的类型:socklen_t

    【讨论】:

      猜你喜欢
      • 2012-04-03
      • 2014-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多