前天同事问我一个关于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