2

I have encountered an issue that inet_ntoa results in segmentation fault on OSX, and this doesn't occur on Linux.

My test code is following.

// sample.c
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
//#include <arpa/inet.h>  // adding this line prevents the segfault

int main() {
    struct sockaddr_in addr;
    struct sockaddr_in client;

    int sock0 = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    addr.sin_addr.s_addr = INADDR_ANY;

    bind(sock0, (struct sockaddr *)&addr, sizeof(addr));
    listen(sock0, 5);

    while (1) {
        int len = sizeof(client);
        int sock = accept(sock0, (struct sockaddr *)&client, (socklen_t *)&len);
        printf("accepted connection from %s, port=%d\n",
               inet_ntoa(client.sin_addr), ntohs(client.sin_port));
        send(sock, "HELLO", 5, 0);
        close(sock);
    }

    close(sock0);

    return 0;
}

I searched for a while and found a solution which is adding an include "arpa/inet.h". I confirmed inet_ntoa is surely declared in inet.h and I'm sure this is correct way.

But I can't understand why this code doesn't work without it. What happens when I build and link this code without the include line?

I know building this code shows warnings "implicit declaration of function", but link error doesn't occur. This means linker found the implementation of inet_ntoa somehow, I think. Is this wrong?

Thanks! Any advice is highly appreciated.

4

2 回答 2

6

我猜你的 OSX 系统是 64 位的,而你的 Linux 系统是 32 位的。假定未声明的函数返回一个整数。如果 64 位指针衰减为作为指针取消引用的 32 位整数,您可能会遇到分段错误。

于 2013-06-17T03:52:20.703 回答
4

C 允许函数的隐式声明(C 中的隐式函数声明)。这就是为什么您没有收到编译器错误的原因。另外 inet_ntoa 在 glibc 中,默认情况下由 gcc 链接,因此链接器会找到函数的定义,因此您不会收到链接器错误。发生段错误是因为 1)C 假定,因为它是隐式声明的,所以函数返回一个 int 和 2)在 glibc 中的 Mac inet_ntoa 上返回一个 64 位指针,该指针被转换为 32 位值并丢失信息。

于 2013-06-17T04:31:52.093 回答