inet_ntoa 陷阱

前天同事问我一个关于ip被"替换"的问题,代码大概如下:

ip_ local = networkMgr.GetLocalIP();  //127.0.0.1
ip_ server = networkMgr.GetServerIP(); //0.0.0.0
printf("  l:%s",inet_ntoa(local));
printf("  s:%s \n",inet_ntoa(server));

//network manager to do something

printf("  l:%s s:%s \n",inet_ntoa(networkMgr.GetLocalIP()),inet_ntoa(networkMgr.GetServerIP()));

/// 输出结果:
// l:127.0.0.1 s:0.0.0.0
// l:0.0.0.0 s:0.0.0.0

"正常情况"下,下边一句应该返回 127.0.0.1 才对.可是为何会发生这种情况? 最初没留意到inet_nota 函数的作用,认为是networkMgr 在处理其他事中改变了本地IP地址导致 networkMgr.GetLocalIP() 获取到新值.熟加数据断点调试(其实不用这么麻烦,直接printf("%u",networkMgr.GetLocalIP()) 便成),发现数据没有被修改。

想起x进制转换成字符串的函数,其形式是:

char* itoa (int value, char * str, int base);

inet_ntoa 函数:

char* inet_ntoa (struct in_addr);

 与inet_ntoa对比,itoa函数的字符串缓冲由参数提供,而inet_ntoa 只需提供 in_addr结构体便可(也可看成是32位无符号整形),说明inet_ntoa返回的字符串缓冲由内部提供。

返回的字符串缓冲要么由堆内存申请,需要自己手动释放;要么是返回内部静态缓冲的地址。

如果是前一种,调用者容易忘记释放内存而做成内存溢出;还有一个问题就是调用者不知道该如何释放,是调用free,还是delete[],还是_aligned_free?这种设计还需提供一个释放内存的接口,明显选择第二种方便快捷简单明了(但需要调用者注意)。

具体查看API文档:http://msdn.microsoft.com/en-us/library/windows/desktop/ms738564(v=vs.85).aspx

其实文档中已经说明内部就是返回内部静态缓冲的地址了。当然也可以直接输出来验证:

char* ls = inet_ntoa(networkMgr.GetLocalIP());
char* ss = inet_ntoa(networkMgr.GetServerIP());

printf(
" l:%p s:%p \n",ls, ss);

至于为何printf 会输出 “ l:0.0.0.0 s:0.0.0.0” 而不是“ l:127.0.0.1 s:127.0.0.1”,这里可以自行查看函数调用约定以及其入栈顺序。例如 stdcall、cdecl等等。

补充:调用inet_ntoa 时还需注意多线程安全问题,建议使用 inet_ntop函数代替。

搜索了下inet_ntoa发现很多人都遇到过类似问题,甚至百度都有大量说明 = =:

C/C++返回内部静态成员的陷阱 http://blog.csdn.net/haoel/article/details/1388498

inet_ntoa使用陷阱: http://hi.baidu.com/lovzs/item/cc9529089bb55e37a3332aa5

inet_ntoa百度百科:http://baike.baidu.com/view/569200.htm

原文地址:https://www.cnblogs.com/godzza/p/2957015.html