2012-04-03 27 views
2

当我用两个字符串使用printf/printf_s时,对于%s变量我都得到相同的输出。printf和多个字符串的不良行为

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 

现在,我已经检查了的oldip和newip值是由打印语句之前打破不同,我也试图让下面的功能和使用它在打印语句(而不是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 

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

回答

6

inet_ntoa retuns:(这是从Linux手册页)

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

你不能在一个函数中使用它两次,只有第二次调用的输出将是可见的(并且你不知道这两个调用中的哪一个是对af的参数进行评估的第二阶次联合未指定)。

做两个单独的printf s,或将inet_ntoa的输出复制到本地缓冲区并输出它们。

POSIX

INET_NTOA(返回值)可以指向可由后续调用被重写到INET_NTOA静态数据()。

所以这种行为很可能不仅限于Linux的,你不能依靠它覆盖静态缓冲区。

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