您的位置:首页 > 其它

函数返回值为指针的一个陷阱(使用inet_ntoa函数时遇到的问题)

2015-06-01 22:03 483 查看
此函数在socket编程中使用,将32位大端序整型格式IP地址转换为点分十进制格式。成功时返回转换的字符串地址值,失败时返回-1。

char * inet_ntoa(struct in_addr addr);


使用一段小代码测试

#include <stdio.h>
#include <arpa/inet.h>

int main(void){
struct in_addr addr1, addr2;
char * str1, * str2;

addr1.s_addr  = htonl(0xc0a80306);
addr2.s_addr  = htonl(0xc0a80308);

str1 = inet_ntoa(addr1);
str2 = inet_ntoa(addr2);

printf("%#lx -> %s \n", (long)addr1.s_addr, str1);
printf("%#lx -> %s \n", (long)addr2.s_addr, str2);

return 0;
}


运行结果

gff@ubuntu:~/cplusplus/ping$ ./inetntoa
0x603a8c0 -> 192.168.3.8
0x803a8c0 -> 192.168.3.8


修改代码如下

#include <stdio.h>
#include <arpa/inet.h>

int main(void){
struct in_addr addr1, addr2;
char * str1, * str2;

addr1.s_addr  = htonl(0xc0a80306);
addr2.s_addr  = htonl(0xc0a80308);

str1 = inet_ntoa(addr1);
printf("%#lx -> %s \n", (long)addr1.s_addr, str1);
str2 = inet_ntoa(addr2);
printf("%#lx -> %s \n", (long)addr2.s_addr, str2);
printf("printf  together\n");
printf("%#lx -> %s \n", (long)addr1.s_addr, str1);
printf("%#lx -> %s \n", (long)addr2.s_addr, str2);

return 0;
}


gff@ubuntu:~/cplusplus/ping$ ./inetntoa
0x603a8c0 -> 192.168.3.6
0x803a8c0 -> 192.168.3.8
printf  together
0x603a8c0 -> 192.168.3.8
0x803a8c0 -> 192.168.3.8


当分别输出时,正确,如果不是,则错误,即第二次调用函数,对第一次调用有影响。

看看函数的返回值,char * 一个函数如何能做到返回一个内存指针,这段内存再什么地方,栈?还是堆?这是一个问题,一般而言是不可以将栈中的地址return出来的,函数调用结束,所分配的栈的生命周期也就结束。

看看这个函数的源代码,看看其是如何实现的。

char *
inet_ntoa (struct in_addr in)
{
__libc_once_define (static, once);
char *buffer;
unsigned char *bytes;

/* If we have not yet initialized the buffer do it now.  */
__libc_once (once, init);

if (static_buf != NULL)
buffer = static_buf;
else
{
/* We don't use the static buffer and so we have a key.  Use it
to get the thread-specific buffer.  */
buffer = __libc_getspecific (key);
if (buffer == NULL)
{
/* No buffer allocated so far.  */
buffer = malloc (18);
if (buffer == NULL)
/* No more memory available.  We use the static buffer.  */
buffer = local_buf;
else
__libc_setspecific (key, buffer);
}
}

bytes = (unsigned char *) ∈
__snprintf (buffer, 18, "%d.%d.%d.%d",
bytes[0], bytes[1], bytes[2], bytes[3]);

return buffer;
}


buffer为静态局部变量

还有一种函数,比如malloc也是返回一个指针地址,但是区别在于,malloc返回的是在堆中开辟的空间,所以在这个空间生命周期结束后要去释放。而用静态局部变量不需要,每次调用包含静态局部变量的函数,在全局区开辟的空间都要覆盖。

其他博主也遇到此问题,如下

http://blog.chinaunix.net/uid-22663647-id-1771824.html

/article/8796441.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: