inet_ntoa使用奇怪的printf行为

#include  #include  #include  #include  #include  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上,这是已知的事情吗?

inet_ntoa的手册页:

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

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

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

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

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

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

因此要么坚持使用两个printfs,要么将inet_ntoa返回的字符串复制到您自己的缓冲区中,然后打印它们。