2010-05-25 35 views
6

Tôi có đoạn mã sau đây để nhận được tên máy và địa chỉ IP,lỗi Segmentation khi nhìn lên tên máy chủ và địa chỉ 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 */ 
} 

Nhưng tôi nhận được một cảnh báo khi biên soạn:

$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’ 

Sau đó, có lỗi phân đoạn khi tôi chạy mã:

./host 192.168.1.4 
Hostname : 192.168.1.4 
Segmentation fault 

Lỗi trong mã là gì?

+4

Bạn đang làm điều gì đó khủng khiếp với cấu trúc vô tội. – SLaks

+0

Nhân tiện, bạn thường không nên sử dụng 'gethostbyname' trong mã mới, chủ yếu vì nó không tương thích với IPv6. Bạn nên sử dụng 'getaddrinfo' thay vào đó: http://beej.us/guide/bgnet/output/html/multipage/getaddrinfoman.html –

+0

Điều gì sẽ xảy ra nếu bạn chạy ./host www.stackoverflow.com? Đó là, nếu bạn sử dụng nó với một tên thực tế chứ không phải là một địa chỉ IP. – nsayer

Trả lời

6

Cảnh báo về sự không phù hợp với định dạng printf là một cảnh báo quan trọng. Trong trường hợp này, nó đến vì trình biên dịch nghĩ rằng hàm inet_ntoa trả về một int, nhưng bạn đã chỉ định để mong đợi một chuỗi trong chuỗi định dạng.

Loại trả về không chính xác cho inet_ntoa là kết quả của quy tắc C cũ quy định rằng nếu bạn cố gắng sử dụng hàm không có khai báo trước, thì trình biên dịch phải giả định hàm trả về int và không xác định (nhưng cố định) số lượng đối số. Sự không khớp giữa kiểu trả về giả định và kiểu trả về thực tế của hàm kết quả là hành vi không xác định, biểu hiện chính nó như là một sự cố trong trường hợp của bạn.

Giải pháp là bao gồm tiêu đề chính xác cho inet_ntoa.

0

Thực ra, tôi vừa biên soạn mã đó trên máy FreeBSD của tôi ở nhà và nó hoạt động.

+0

Tôi đã thử mà không cần #include trên Mac OS và nó đã đưa ra cảnh báo và có lỗi Phân đoạn – Biranchi

0

Bạn có thể thử bán phá giá trị he->h_addr trước khi cố gắng dereference nó và vượt qua nó để inet_ntoa. Nếu nó là NULL, điều đó sẽ dẫn đến lỗi seg.

Làm thế nào để chạy nó qua strace?

1

Nghỉ mã này:

printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr))); 

Into này:

struct in_addr* address = (in_addr*) he->h_addr; 
char* ip_address = inet_ntoa(*address); 
printf("IP address: %s\n", ip_address); 

Nó cũng làm cho nó dễ dàng hơn để gỡ lỗi và xác định được vấn đề.

8

Tôi có một mã tương tự (nếu không giống nhau) và nó được biên dịch tốt trong máy trong phòng thí nghiệm của trường, nhưng khi tôi biên dịch trên máy của tôi ở nhà, nó có cùng lỗi (tôi không sửa mã). Tôi đọc trang người đàn ông cho inet và thấy rằng tôi đã thiếu một tệp tiêu đề, là #include <arpa/inet.h>. Sau khi tôi thêm tiêu đề đó vào chương trình C của tôi, nó đã biên dịch và chạy tốt.

+1

Đã làm việc cho tôi. Cảm ơn rất nhiều! –

Các vấn đề liên quan