问题
有一个IP地址"127.0.0.1" 需要他的四字节整型值?
反过来有一个整型值,如何转换为一个点分十进制的IP地址?
其实libc是提供这个接口的,不需要自己再造轮子,对比我们自己的实现,用到了联合体,非常值得学习,如下:
1、inet_addr
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
/*
* Ascii internet address interpretation routine.
* The value returned is in network order.
*/
in_addr_t
__inet_addr(const char *cp) {
struct in_addr val;
if (__inet_aton(cp, &val))
return (val.s_addr);
return (INADDR_NONE);
}
weak_alias (__inet_addr, inet_addr)
/*
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*/
int
__inet_aton(const char *cp, struct in_addr *addr)
{
static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff };
in_addr_t val;
char c;
union iaddr {
uint8_t bytes[4];
uint32_t word;
} res;
uint8_t *pp = res.bytes;
int digit;
int saved_errno = errno;
__set_errno (0);
res.word = 0;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, isdigit=decimal.
*/
if (!isdigit(c))
goto ret_0;
{
char *endp;
unsigned long ul = strtoul (cp, (char **) &endp, 0);
if (ul == ULONG_MAX && errno == ERANGE)
goto ret_0;
if (ul > 0xfffffffful)
goto ret_0;
val = ul;
digit = cp != endp;
cp = endp;
}
c = *cp;
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp > res.bytes + 2 || val > 0xff)
goto ret_0;
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && (!isascii(c) || !isspace(c)))
goto ret_0;
/*
* Did we get a valid digit?
*/
if (!digit)
goto ret_0;
/* Check whether the last part is in its limits depending on
the number of parts in total. */
if (val > max[pp - res.bytes])
goto ret_0;
if (addr != NULL)
addr->s_addr = res.word | htonl (val);
__set_errno (saved_errno);
return (1);
ret_0:
__set_errno (saved_errno);
return (0);
}
weak_alias (__inet_aton, inet_aton)
libc_hidden_def (__inet_aton)
libc_hidden_weak (inet_aton)
2、inet_ntoa 看源码还是相对比较简单,就是格式化字符串
/* The interface of this function is completely stupid, it requires a
static buffer. We relax this a bit in that we allow one buffer for
each thread. */
static __thread char buffer[18];
char *
inet_ntoa (struct in_addr in)
{
unsigned char *bytes = (unsigned char *) ∈
__snprintf (buffer, sizeof (buffer), "%d.%d.%d.%d",
bytes[0], bytes[1], bytes[2], bytes[3]);
return buffer;
}
3、测试
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
int main()
{
unsigned long a = inet_addr("127.0.0.1");
printf("a is %d\r\n", a);
struct in_addr addr1;
addr1.s_addr = a;
char *p = inet_ntoa(addr1);
printf("p is %s\r\n", p);
return 0;
}
4、运行结果
完结,注意inet_addr转换后是一个网络字节序,也就是大端,如果是本地使用还需要注意哈。