printf和多个字符串的错误行为

Bad behavior with printf and multiple strings

本文关键字:错误 字符串 printf      更新时间:2023-10-16

当我将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

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

inet_ntoa重新运行:

一个静态分配的缓冲区,随后的调用覆盖

(这来自Linux手册页。)

您不能在函数中使用它两次,只有第二次调用的输出是可见的(您不知道两次调用中的哪一次是第二次,函数参数的求值顺序未指定)。

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

来自POSIX:

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

因此,这种行为可能不局限于Linux,并且您不能依赖它而不是覆盖静态缓冲区。

由于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时,它可以自由地覆盖其先前存储的值。