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

涉及静态变量和fprintf的奇怪C行为,c,linux,network-programming,C,Linux,Network Programming,我正在为现有的大型软件工具添加一项功能(该工具用于dns数据包捕获和解析等)。我注意到原始代码中有一些奇怪的东西,无法理解解释是什么。代码具有存储IP地址(IPv6和IPv4)的结构,如下所示: typedef struct { int af; union { struct in_addr a4; struct in6_addr a6; } u; } iaddr; 此外,它还具有将存储的地

我正在为现有的大型软件工具添加一项功能(该工具用于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,也会发生这种情况):

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


我被难住了。请帮忙。提前谢谢

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


因此,对ia_str()的两个调用都是在设置对fprintf()的调用之前计算的。ia_str()的返回值被推送到堆栈中,但由于它是一个静态缓冲区,因此它包含最后放入堆栈中的值。这很可能是因为ia_str()正在返回指向静态缓冲区的指针


因此,对ia_str()的两个调用都是在设置对fprintf()的调用之前计算的。ia_str()的返回值被推送到堆栈中,但由于它是一个静态缓冲区,因此它包含最后放入堆栈中的值。恰好是from is_str(from)。

到fprint如果传递相同的地址,因为从ia_str返回将在任意次数的调用中返回相同的地址,因此只有最后一次调用的更改有效。因此,当调用fprintf时,最后调用的函数ia_str(from)[函数将从右向左调用]将修改ret,并且只有该函数才会出现。它将是这样的:

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

相同的地址,所以相同的值。

到fprint如果传递相同的地址,因为从ia_str返回将在任意次数的调用中返回相同的地址,只有最后一次调用的更改将保持有效。因此,当调用fprintf时,最后调用的函数ia_str(from)[函数将从右向左调用]将修改ret,并且只有该函数才会出现。它将是这样的:

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

相同的地址,所以相同的值。

换句话说,ia_str()不是可重入的+1股!现在看来很明显,我觉得自己很笨。:-)换句话说,ia_str()不是可重入的+1股!现在看来很明显,我觉得自己很笨。:-)+1.很好地阐述问题。很久以前,我也被inet_ntoa难住了,它使用了静态缓冲区,比如函数ia_str()。您还应该使用_线程修饰符(如果使用Glibc)来分隔多个线程的缓冲区。@basilestrynkevitch谢谢,但是sizeof(“abc”)==4。所以,我不相信你是对的;除非我误解了什么。用户138645谢谢。这个项目没有使用Glibc,但我可能最终会使用它,所以很高兴知道这一点。+1用于很好地构建问题。很久以前,我也被inet_ntoa难住了,它使用了静态缓冲区,比如函数ia_str()。您还应该使用_线程修饰符(如果使用Glibc)来分隔多个线程的缓冲区。@basilestrynkevitch谢谢,但是sizeof(“abc”)==4。所以,我不相信你是对的;除非我误解了什么。用户138645谢谢。这个项目没有使用Glibc,但我可能最终会使用它,所以很高兴知道。谢谢!解释得很好。我接受@Ziffusion的答案,因为这是第一个答案,但你的答案同样清楚。现在看来很明显。:-)谢谢解释得很好。我接受@Ziffusion的答案,因为这是第一个答案,但你的答案同样清楚。现在看来很明显。:-)