Ошибка сегментации при поиске имени хоста и IP-адреса
У меня есть следующий кусок кода для получения имени хоста и IP-адреса,
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h> /* This is the header file needed for gethostbyname() */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
struct hostent *he;
if (argc!=2){
printf("Usage: %s <hostname>\n",argv[0]);
exit(-1);
}
if ((he=gethostbyname(argv[1]))==NULL){
printf("gethostbyname() error\n");
exit(-1);
}
printf("Hostname : %s\n",he->h_name); /* prints the hostname */
printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr))); /* prints IP address */
}
Но я получаю предупреждение во время компиляции:
$cc host.c -o host
host.c: In function ‘main’:
host.c:24: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
Затем возникает ошибка сегментации, когда я запускаю код:
./host 192.168.1.4
Hostname : 192.168.1.4
Segmentation fault
В чем ошибка в коде?
5 ответов
Предупреждение о несоответствии для формата printf является важным предупреждением. В этом случае это происходит потому, что компилятор считает, что функция inet_ntoa
возвращает int
, но вы указали ожидать строку в формате-строки.
Неверный тип возврата для inet_ntoa
является результатом старого правила C, которое гласит, что если вы попытаетесь использовать функцию без предварительного объявления, то компилятор должен предположить, что функция возвращает int
и принимает неизвестное (но фиксированное) количество аргументов. Несоответствие между предполагаемым типом возврата и фактическим типом возврата функции приводит к неопределенному поведению, которое в вашем случае проявляется как сбой.
Решение состоит в том, чтобы включить правильный заголовок для inet_ntoa
,
У меня был похожий код (если не тот же самый), и он отлично скомпилировался на машине в нашей школьной лаборатории, но когда я скомпилировал его на своей машине дома, у него была та же ошибка (я не редактировал код). Я прочитал справочную страницу для inet
и обнаружил, что у меня пропал один заголовочный файл, который является #include <arpa/inet.h>
, После того, как я добавил этот заголовок в мою C-программу, он скомпилировался и работал нормально.
Сломать этот код:
printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr)));
В это:
struct in_addr* address = (in_addr*) he->h_addr;
char* ip_address = inet_ntoa(*address);
printf("IP address: %s\n", ip_address);
Это также облегчает отладку и точное определение проблемы.
Вы можете попробовать сбросить значение he->h_addr
прежде чем пытаться разыменовать его и передать его inet_ntoa
, Если бы это было NULL
, что приведет к ошибке сегмента.
Как насчет того, чтобы пройти через strace
?
На самом деле, я просто скомпилировал этот код на моей машине с FreeBSD дома, и он работает.