从一段代码开始:
int test_ntoa()
{
struct sockaddr_in recv = {0};
struct sockaddr_in sa = {0};
recv.sin_addr.s_addr = -217732928; //192.168.5.243
sa.sin_addr.s_addr = -939415360; //192.168.5.200
printf("ip of recv:%s ip of sa:%s\n", inet_ntoa(recv.sin_addr), inet_ntoa(sa.sin_addr));
printf("ip of recv:%s\n", inet_ntoa(recv.sin_addr));
printf("ip of sa :%s\n", inet_ntoa(sa.sin_addr));
return 0;
}
结果有点诧异:
ip of recv:192.168.5.243 ip of sa:192.168.5.243
ip of recv:192.168.5.243
ip of sa :192.168.1.200
C函数出现这类问题,多半是由于其实现使用了静态内存所知.
google其源码:
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,函数把转换后的ip写入缓存buffer,然后返回buffer的首地址值.
看似无奈的选择.glibc里的某些底层函数都使用这类处理方式.
其实也可以选择外部传参的做法解决:
这样的处理方式,效率略低于第一种.或许这也是glibc选择第一种方式的原因.char * inet_ntoa (struct in_addr in, char* buf, int buflen) { ... ... }