强制类型转换中的精度丢失
最近在写unix网络程序的时候,需要完成一个很简单的程序,将输入的十六进制数转成字符串形式的IP地址,代码如下:
1 /************************************************************************* 2 > File Name: hex2add.c 3 > Author: cat 4 > Mail: luojinfu1988@163.com 5 6 ************************************************************************/ 7 8 #include<stdio.h> 9 #include<stdlib.h> 10 #include <sys/socket.h> 11 #include <netinet/in.h> 12 #include <arpa/inet.h> 13 14 int main(int argc, char **argv) 15 { 16 if (argc != 2) { 17 printf("usage: %s <addr>\n", argv[0]); 18 exit(-1); 19 } 20 21 unsigned int temp = (unsigned int) strtol(argv[1], NULL, 16); 22 23 struct in_addr addr; 24 addr.s_addr = htonl(temp); 25 printf("the ip address is %s\n", inet_ntoa(addr)); 26 27 return 0; 28 }
但是输出的结果却不正确,0xffffffff 应该转化成 255.255.255.255 才对,为什么结果会转化错呢?
使用gdb调试的时候发现,strtol 函数转换出问题了,strtol函数的返回值是int类型,能够表达的值达不到0xffffffff作为无符号数的值。
比如,char 的取值范围是 -128 ~ 127, unsigned char 的取值范围是 0 ~ 255。 所以 有可能会出错。
strtol 函数的行为有点怪,将接受到的字符串*nptr 按照无符号转换,通过前置的+ 和 - 来决定正负,而不是最高位。当转换结果相对应 int类型溢出时,就会被截断。
1 /************************************************************************* 2 > File Name: hex2add.c 3 > Author: cat 4 > Mail: luojinfu1988@163.com 5 6 ************************************************************************/ 7 8 #include<stdio.h> 9 #include<stdlib.h> 10 #include <sys/socket.h> 11 #include <netinet/in.h> 12 #include <arpa/inet.h> 13 14 int main(int argc, char **argv) 15 { 16 if (argc != 2) { 17 printf("usage: %s <addr>\n", argv[0]); 18 exit(-1); 19 } 20 21 unsigned int temp = (unsigned int) strtoll(argv[1], NULL, 16); //此处我们也可以选择sscanf 函数来替换,效果更好。 22 23 struct in_addr addr; 24 addr.s_addr = htonl(temp); 25 printf("the ip address is %s\n", inet_ntoa(addr)); 26 27 return 0; 28 }