【问题标题】:Weird printf behaviour with inet_ntoainet_ntoa 的奇怪 printf 行为
【发布时间】:2015-11-08 12:15:52
【问题描述】:
#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 上,这是已知的吗?

【问题讨论】:

    标签: c sockets printf


    【解决方案1】:

    来自inet_ntoa 的手册页:

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

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

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • 我倾向于使用inet_ntop 来避免这个问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多