printf和多个字符串的不良行为

时间:2012-04-03 20:03:35

标签: c++ printf inet

当我使用带有两个字符串的printf / printf_s时,我得到%s变量的相同输出。

IN_ADDR oldIP;
oldIP.S_un.S_addr = iptable[j]->ipAddress;
IN_ADDR newIP;
newIP.S_un.S_addr = adapterTbl->table[i].dwAddr;
printf_s("index %d old: %s new: %s", 
          adapterTbl->table[i].dwIndex, inet_ntoa(oldIP),
           inet_ntoa(newIP));

输出是:

index 11 old: 192.168.1.1 new: 192.168.1.1

现在,我已经通过在print语句之前断开来检查oldip和newip的值是不同的,我还尝试使用以下函数并在print语句中使用它(而不是inet_ntoa):

char *convertIP (DWORD ip)  
{  
    IN_ADDR *addr = new IN_ADDR;
    memset(addr, 0, sizeof(IN_ADDR));
    addr->S_un.S_addr = (u_long) ip;
    return inet_ntoa(*addr);
} 

这个输出是:

192.168.1.1
192.168.1.2
index 11 old: 192.168.1.1 new: 192.168.1.1

为什么我会看到这种行为,我该如何解决? 谢谢:))

2 个答案:

答案 0 :(得分:6)

inet_ntoa返回:

  

静态分配的缓冲区,后续调用覆盖

(这是来自Linux联机帮助页。)

你不能在函数中使用它两次,只有第二次调用的输出才会可见(并且你不知道这两个调用中的哪一个是第二个 - 函数参数的评估顺序是未指定)。

执行两个单独的printf,或将inet_ntoa的输出复制到本地缓冲区并输出。

来自POSIX

  

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

所以这种行为可能不仅限于Linux,你也不能依赖它而不是覆盖静态缓冲区。

答案 1 :(得分:1)

出于Mat描述的原因,您必须在执行下一次呼叫之前使用对inet_ntoa的一次呼叫的结果。

这是一种简单的方法:

IN_ADDR oldIP;
oldIP.S_un.S_addr = iptable[j]->ipAddress;
IN_ADDR newIP;
newIP.S_un.S_addr = adapterTbl->table[i].dwAddr;
std::string s_old(inet_ntoa(oldIP));
std::string s_new(inet_ntoa(newIP));
printf_s("index %d old: %s new: %s", 
      adapterTbl->table[i].dwIndex, s_old.c_str(),
       s_new.c_str());

请注意,string构造函数会复制传入的C字符串。因此,当再次调用inet_ntoa时,可以自由覆盖其先前存储的值。