难以理解C ++中inet_ntop()的第二个参数

时间:2017-06-20 05:52:49

标签: c++

我正在尝试基于此处给出的教程在C ++中创建基本的Web服务器:

https://vichargrave.github.io/articles/2013-02/tcp-ip-network-programming-design-patterns-in-cpp

我无法理解以下内容:

inet_ntop(PF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, sizeof(ip)-1);

具体来说,我无法理解第二个参数:

(struct in_addr*)&(address->sin_addr.s_addr)

正在做。这个参数是我以前没有见过的语法,基于我所知道它正在做两件事之一:

它是一个结构in_addr指针与地址或

中的给定字段

它将address->sin_addr.s_addr的地址转换为指针struct in_addr*

是哪一个?

编辑: 所以它似乎是演员。这引出了另一个问题。该参数似乎是将类型in_addr_t的变量强制转换为一个没有意义的结构。这是对它的正确看法还是做其他事情?

此外,我正在引用以下页面以获取有关此功能的文档:

http://pubs.opengroup.org/onlinepubs/7908799/xns/netinetin.h.html http://pubs.opengroup.org/onlinepubs/009695399/functions/inet_ntop.html

2 个答案:

答案 0 :(得分:1)

为了更好地理解,请从右到左阅读。

(struct in_addr*)&(address->sin_addr.s_addr)

所以,

address->sin_addr.s_addr --> uses the "address" ptr to access sin_addr.s_addr

然后

&(address->sin_addr.s_addr) takes the address of s_addr.

然后

(struct in_addr*) casts the address taken by & to in_addr.

以上是有道理的,因为在这种情况下,以下2是等效的

(struct in_addr*)&(address->sin_addr.s_addr) 
(struct in_addr*)&(address->sin_addr)

结构的地址与C / C ++中第一个成员的地址相同。

答案 1 :(得分:1)

要回答您的第一个问题,它确实将address->sin_addr.s_addr字段的地址转换为struct in_addr*指针。由于问题标记为c++,因此C ++样式转换会更清晰:

inet_ntop(PF_INET, reinterpret_cast<struct in_addr*>(&(address->sin_addr.s_addr)), ip, sizeof(ip)-1);

要回答第二个问题,它不会将变量本身转换为指针。它将变量的地址转换为不同的指针类型。在这种情况下,s_addr字段的地址将转换为struct in_addr*指针。类型的第一个字段的地址与类型本身的地址相同。因此,将s_addr地址转换为struct in_addr*在技术上是安全的。

然而,话虽如此,演员阵容是多余的,应该被删除。 inet_ntop()的第二个参数是const void*,任何指针都可以as_is指定给void*。当第一个参数为(AF|PF)_INET时,第二个参数必须是指向struct in_addr的指针,因此您应该使用sin_addr字段本身的地址(这是一个实际in_addr }),而不是s_addr字段(in_addr内的字段):

inet_ntop(AF_INET, &(address->sin_addr), ip, sizeof(ip)-1);

如果您有IPv6地址(第一个参数是(AF|PF)_INET6),则第二个参数必须是指向struct in6_addr的指针,该sin6_addr字段是sockaddr_in6的{​​{1}}字段。 1}}:

inet_ntop(AF_INET6, &(address->sin6_addr), ip, sizeof(ip)-1);

为了支持两个家庭(首先使用inet_ntop()的主要原因),address应该是指向struct sockaddr_storage的指针(大到足以容纳任何一个) struct sockaddr_...类型,但在这种情况下为IPv4和IPv6地址),ip需要至少46个字符(最好使用INET6_ADDRSTRLEN定义)。然后,您可以执行以下操作:

switch (address->ss_family) 
{
    case AF_INET:
        inet_ntop(AF_INET, &(reinterpret_cast<struct sockaddr_in*>(address)->sin_addr), ip, sizeof(ip)-1);
        break;
    case AF_INET6:
        inet_ntop(AF_INET6, &(reinterpret_cast<struct sockaddr_in6*>(address)->sin6_addr), ip, sizeof(ip)-1);
        break;
}