inet_ntoa使用奇怪的printf行为

时间:2015-11-08 12:15:53

标签: c sockets printf

#include <sys/socket.h>
#include <err.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char **argv) {

    struct sockaddr_in X = {0};
    X.sin_family = AF_INET;
    X.sin_addr.s_addr = inet_addr("127.0.0.1");
    X.sin_port = htons(8080);

    struct sockaddr_in Y = {0};
    Y.sin_family = AF_INET;
    Y.sin_addr.s_addr = inet_addr("212.43.159.20");
    Y.sin_port = htons(80);

    printf("X:Y %s:%s\n", inet_ntoa(X.sin_addr), inet_ntoa(Y.sin_addr));
    printf("X %s\n", inet_ntoa(X.sin_addr));
    printf("Y %s\n", inet_ntoa(Y.sin_addr));

    return 0;
}

为什么第一个pritnf打印相同的IP两次而不是给出什么? 第二和第三似乎没问题。 似乎发生在linux gcc / clang和freebsd clang上,这是已知的事情吗?

2 个答案:

答案 0 :(得分:4)

来自inet_ntoa的手册页:

  

inet_ntoa()函数转换给定的Internet主机地址   以网络字节顺序到标准数字和点的字符串   符号。 字符串在静态分配的缓冲区中返回,   后续调用将覆盖哪些。

由于inet_ntoa使用静态缓冲区作为其输出,并且因为在一次函数调用中调用它两次,printf会传递两个相同指针的副本。它包含最后一次调用的内容。

您需要将打印分成两个单独的调用,就像您在以下行中一样。

答案 1 :(得分:2)

查看inet_ntoa的POSIX文档,值得注意的是“应用程序用法”部分:

  

inet_ntoa() 的返回值可能指向可能被后续调用覆盖到inet_ntoa()的静态数据。

这就是这里发生的事情:第一个printf中的两个调用之一是覆盖另一个调用(并且您不知道哪一个 - 函数参数的评估顺序是实现定义的)。

所以要么坚持使用两个printfs,要么将inet_ntoa返回的字符串复制到自己的缓冲区中,然后打印出来。