gethostbyname()返回一个带负地址的结构

时间:2017-06-26 15:20:36

标签: c gethostbyname

我正在编写一个程序来检查给定网址或IP上的端口是否打开。为了获得给定网址的IP地址,我使用gethostbyname()。当尝试查找localhost的地址时,它返回正确的值,但是,尝试查找它通常失败的远程主机的地址并返回带有负数的ip地址。例如:

/test.out google.com
ip: -40.58.-42.78

/test.out reddit.com
ip: -105.101.-127.-116

./test.out facebook.com
ip: 31.13.84.36

奇怪的是,最后一个有效。这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>

int main(int argc, char **argv)
{
    struct hostent *he;
    struct in_addr **addr_list;

    if ((he = gethostbyname(argv[1])) == NULL) {
        herror("gethostbyname");
        return 1;
    }

    printf("ip: ");
    for (int i = 0; i < he->h_length; i++) {
        printf("%d", he->h_addr_list[0][i]);
        if (i != he->h_length - 1) printf(".");
    }
    printf("\n");
}

另外,为什么h_addr_list char **的类型?不应该是整数,还是更好的无符号?

2 个答案:

答案 0 :(得分:4)

IP地址的组成部分是无符号字节,但在struct hostent中,它们存储为char(即已签名)。这意味着值128 .. 255被解释为负数。

您使用%d格式打印它们,这些格式将值打印为已签名,因为这是它接收它们的方式。将值传递给unsigned char时,将值转换为unsigned int(或printf(),如果您愿意):

printf("%d", (unsigned char)he->h_addr_list[0][i]);

您也可以使用%u代替%d(它将其收到的值视为unsigned),但您仍需要转换值以传递给{{1} }} 1

unsigned

另一种选择是强制printf("%u", (unsigned char)he->h_addr_list[0][i]); 仅使用它获得的值的最低有效字节,并使用printf()将其打印为无符号。但是,这看起来更像是一个黑客,而不是正确的解决方案。

1 没有转换,因为"%hhu"variadic function,从printf()提升作为参数(he->h_addr_list[0][i])传递给它的值到(signed) char。使用(signed) int打印它们会为大于"%u"的组件生成非常大的数字而不是负数。

答案 1 :(得分:2)

这个答案特别针对h_addr_list的类型。

在发明gethostbyname的古代BSD程序员的脑海中,它将用于查找各种网络地址,而不仅仅是IP地址。这就是为什么它也有h_addrtype的原因。 h_addr_list[n]的解释取决于h_addrtype。对于h_addrtype==AF_INET,地址是您熟悉的4字节IP地址格式。对于其他地址类型,可能是其他类型。

char **类型的h_addr_list应理解为&#34;动态分配的不透明缓冲区数组&#34;。可能是void **void尚未发明。

事实证明,IPv4成为唯一关注的网络协议,直到IPv6出现,然后决定完全替换主机查找接口(参见getaddrinfo)。因此,在野外看到非AF_INET h_addrtype的机会很少。