Ошибка сегментации при поиске имени хоста и 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 дома, и он работает.

Другие вопросы по тегам