涉及静态变量和fprintf的奇怪C行为

时间:2013-02-06 03:58:15

标签: c linux network-programming

我正在为现有的大型软件工具添加功能(该工具用于dns数据包捕获和解析等)。我注意到原始代码中有些奇怪的东西,无法弄清楚解释是什么。该代码具有用于存储IP地址(IPv6和IPv4)的结构,如下所示:

typedef struct {
    int         af;  
    union {
        struct in_addr      a4;  
        struct in6_addr     a6;  
    } u; 
} iaddr; 

此外,它具有将如此存储的地址转换为字符串的功能:

static const char * ia_str(iaddr ia) {                                  
    static char ret[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
    (void) inet_ntop(ia.af, &ia.u, ret, sizeof ret);
    return (ret);
}

现在,在打印数据包时,代码执行类似的操作来打印源和目标地址和端口:

void output(const char *descr, iaddr from, iaddr to, ...
    ...
    fprintf(stderr, "%s:%u ", ia_str(from), sport);
    fprintf(stderr, "-> %s:%u", ia_str(to), dport);

到目前为止,这么好(我想)。这是已发布的代码,似乎工作正常。现在,当我做出这个微小的微小变化时,简单地将上面两个fprintf线组合成一个(如果我尝试使用sprintf而不是fprintf,也会发生这种情况):

    fprintf(stderr, "%s:%u -> %s:%u", ia_str(from), sport, ia_str(to), dport);

程序在两个位置打印相同的地址(即ia_str(from)地址)!

我很难过。请帮忙。提前谢谢!

2 个答案:

答案 0 :(得分:3)

这很可能是因为ia_str()返回一个指向静态缓冲区的指针。

所以,会发生的事情是在调用fprintf()之前计算对ia_str()的调用。 ia_str()的返回值被推送到堆栈,但因为它是一个静态缓冲区,所以它包含最后放在那里的值。恰好来自is_str(from)。

答案 1 :(得分:2)

为了fprintf传递相同的地址,因为从ia_str返回将在任意数量的调用中返回相同的地址,只有最后一次调用的更改才能保持良好状态。因此,当调用fprintf时,最后一个调用函数ia_str(from)[函数将从右向左调用]将修改ret,并且只有那个才会出现。它将是这样的:

fprintf(stderr, "%s:%u -> %s:%u", 0x12345, sport, 0x12345, dport);

相同的地址,同样的价值。