冷胜魁(Seaquester)
lengshengkui@gmail.com
2011-9-14
有这样一段简单的代码,在32位Linux(CentOS 6)下没有问题,但是,拿到64位Linux(CentOS 6)下运行就会出现段错误。
- #include <stdio.h>
- #include <string.h>
- #include <netdb.h>
- #include <sys/types.h>
- #include <sys/socket.h>
-
-
- int get_host_ip(const char* server)
- {
- struct addrinfo *result = NULL;
- int ret;
- struct addrinfo addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.ai_socktype = SOCK_STREAM;
-
- ret = getaddrinfo(server, NULL, &addr, &result);
- if (ret) {
- perror("getaddrinfo");
- return ret;
- }
-
- struct addrinfo *pCurr = result;
- printf("%s:\n", server);
- for (; pCurr; pCurr = pCurr->ai_next) {
- printf("%s\n", inet_ntoa(((struct sockaddr_in*)(pCurr->ai_addr))->sin_addr));
- }
- printf("\n");
-
- freeaddrinfo(result);
- return 0;
- }
-
-
- int main()
- {
- get_host_ip("localhost");
- return 0;
- }
运行结果如下:
- [shengkui@uranus code]$ ./getaddr
- chinaunix.net:
- Segmentation fault (core dumped)
很奇怪,通过gdb来调试了一下:
- [shengkui@uranus code]$ gcc -g -o getaddr getaddr.c
- [shengkui@uranus code]$ gdb ./getaddr
- GNU gdb (GDB) Red Hat Enterprise Linux (7.1-29.el6)
- Copyright (C) 2010 Free Software Foundation, Inc.
- License GPLv3 : GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
- This is free software: you are free to change and redistribute it.
- There is NO WARRANTY, to the extent permitted by law. Type "show copying"
- and "show warranty" for details.
- This GDB was configured as "x86_64-redhat-linux-gnu".
- For bug reporting instructions, please see:
- <http://www.gnu.org/software/gdb/bugs/>...
- Reading symbols from /home/shengkui/work/code/getaddr...done.
- (gdb) run
- Starting program: /home/shengkui/work/code/getaddr
- localhost:
- Program received signal SIGSEGV, Segmentation fault.
- 0x000000317a247fe7 in vfprintf () from /lib64/libc.so.6
- Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.x86_64
- (gdb) bt
- #0 0x000000317a247fe7 in vfprintf () from /lib64/libc.so.6
- #1 0x000000317a24ef8a in printf () from /lib64/libc.so.6
- #2 0x0000000000400736 in get_host_ip (server=0x40088d "localhost") at getaddr.c:28
- #3 0x0000000000400774 in main () at getaddr.c:40
- (gdb) f 2
- #2 0x0000000000400736 in get_host_ip (server=0x40088d "localhost") at getaddr.c:28
- 28 printf("%s\n", inet_ntoa(((struct sockaddr_in*)(pCurr->ai_addr))->sin_addr));
- (gdb) quit
发现出错在 inet_ntoa 那一行。查看了 inet_ntoa 的帮助,没有发现什么特别的地方。
试着打开编译的warning开关看看有没有什么发现:
- [shengkui@uranus ~]$ gcc -g -o getaddr getaddr.c -Wall
- getaddr.c: In function 'get_host_ip':
- getaddr.c:26: warning: implicit declaration of function 'inet_ntoa'
- getaddr.c:26: warning: format '%s' expects type 'char *', but argument 2 has type 'int'
inet_ntoa 没有声明,是因为没有加必须的头文件。
inet_ntoa 的返回值是 “char *”, 而编译器似乎把它的返回值当成了int?是这个导致的错误吗?
在64位的Linux 下,int是32位的,而指针(在这里是 char *)是64位的。问题应该就是出在这里!
我把 inet_ntoa 需要的头文件加上去:
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
编译,运行,结果正确,没有段错误!
这个问题提醒我们,函数的声明不是可有可无的,不要小看任何一个warning。