我正在编写一个程序来检查给定 url 或 ip 上的端口是否打开。为了获得给定 url 的 ip 地址,我使用了 gethostbyname()
。当尝试查找本地主机的地址时,它会返回正确的值,但是,尝试查找远程主机的地址时,它通常会失败并返回一个带有负数的 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 **
?它不应该是一个整数,或者更好的是一个无符号整数吗?
最佳答案
IP 地址的组成部分是无符号字节,但在 struct hostent
中,它们存储为 char
(即已签名)。这意味着值 128
..255
被解释为负数。
您使用 %d
格式打印它们,该格式将值打印为带符号的,因为这是它接收它们的方式。当您将值传递给 printf()
时,将值转换为 unsigned char
(或 unsigned int
,如果您愿意):
printf("%d", (unsigned char)he->h_addr_list[0][i]);
您也可以使用 %u
而不是 %d
(它将接收到的值视为 unsigned
),但您仍然需要将要传递给它的值转换为 unsigned
1:
printf("%u", (unsigned char)he->h_addr_list[0][i]);
另一种选择是强制 printf()
仅使用它获取的值的最低有效字节并将其打印为无符号,使用 "%hhu"
。然而,这看起来更像是一种 hack,而不是正确的解决方案。
1 没有转换,因为 printf()
是 variadic function ,作为参数 (he->h_addr_list[0][i]
) 传递给它的值从 (signed) char
提升为 (signed) int
。对于大于 127
的组件,使用 "%u"
打印它们会产生非常大的数字而不是负数。
关于c - gethostbyname() 返回具有负地址的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44763040/