inet_ntoa不可重入性

在使用inet_ntoa时, 碰到一个很奇观的现象。

代码如下:

fprintf(stdout, "recv from %s:%d %d and send to %s:%d %d\\n",
 inet\_ntoa(from.sin\_addr), ntohs(from.sin\_port), len,
 inet\_ntoa(to.sin\_addr), ntohs(to.sin\_port), s);

分析输出log, 发现除了to.sin_addr, 其他参数都是正确的;to.sin_addr的输出值为from.sin_addr值;但使用gdb来debug发现, to.sin_addr是正确的,也就是说输出到标准输出设备(stdout)上的值, 不是to.sin_addr的值。

查看inet_ntoa的在线手册:

The inet_ntoa() function converts the Internet host address in, given in network byte order, to a string in IPv4 dotted-decimal notation. The string is returned in a statically allocated buffer, which subsequent calls will overwrite.

很明显, inet_ntoa是不可重入的,每次调用都返回已分配好的一段memory地址,也就是说inet_ntoa的返回值(一个char*指针)是固定的,但memory中包含的内容不一样。 在上述代码中, 在计算fprintf参数时, inet_ntoa被调用了两次,第一次的调用结果被第二次覆盖住;输出结果也反应了参数的入栈顺序为从右到左。

结论:

  • inet_ntoa 是不可重入的,在多线程的环境下要更加注意
  • 每次调用inet_ntoa都会覆盖上次调用的计算结果, 要注意保存结果

另外, 为support IPV6, 推荐使用inet_ntop函数。