关于atoi的一个坑

先说一下环境:
1.windows 7   32bit ,vs2005

问题的现象:

是一个关于两个ip计算是否是同一个网段的问题,ip和掩码均使用字符串保存的32位无符号整型,在计算的时候使用atoi转换成整型,然后使用&与运算计算两个ip是否在同一网段,但是却将同一网段的两个ip计算成两个不同网段的ip,详细见代码:

#include
#include
int main()
{
unsigned int src = 1280134664 ; //0x4C4D4E08;
unsigned int dest = 1280134664 ; //0x4C4D4E11;
unsigned int mask = 1280134664 ; //0xFFFFFF00;
 
const char* szSrc = "1280134664"; //0x4C4D4E08
const char* szDest = "1280134673"; //0x4C4D4E11
const char* szMask = "4294967040"; //0xFFFFFF00
 
printf("the result is %d\n", (src & mask) == (dest & mask)); //数值运算
 
printf("ths string result is %d\n", (atoi(szSrc) & atoi(szMask)) ==
(atoi(szDest) & atoi(szMask))); //字符串运算
 
return 0;
}

结果如图:

 

OK,造成这个结果的原因是什么呢?看一下msdn对此函数的返回值的解释:

Return Value

Each function returns the int value produced by interpreting the input characters as a number. The return value is 0 for atoi and _wtoi, if the input cannot be converted to a value of that type.

In the case of overflow with large negative integral values, LONG_MIN is returned.  atoi and _wtoi return INT_MAX and INT_MIN on these conditions. In all out-of-range cases, errno is set to ERANGE. If the parameter passed in is NULL, the invalid parameter handler is invoked, as described in Parameter Validation. If execution is allowed to continue, these functions set errno to EINVAL and return 0.

通过msdn看到atoi在超过最大正整数的时候会返回INT_MAX   在32位环境下, INT_MAX的定义为:

#define INT_MAX       2147483647

所以他并不会按照字符串的字面值的大小自动翻转符号,所以mask的实际的返回值是2147483647,结果相当于:0X7FFFFFFF,所以两个IP计算出来会出现不在一个网段的情况

解决方法:

在需要将一个字符串转换到unsigned int 类型的时候,使用_atoi64()函数,64位足够包含unsigned int,修改之后的代码如下:

#include 
 
#include 
 
int main()
 
{
 
unsigned int src = 1280134664 ; //0x4C4D4E08;
 
unsigned int dest = 1280134664 ; //0x4C4D4E11;
 
unsigned int mask = 1280134664 ; //0xFFFFFF00;
 
const char* szSrc = "1280134664"; //0x4C4D4E08
 
const char* szDest = "1280134673"; //0x4C4D4E11
 
const char* szMask = "4294967040"; //0xFFFFFF00
 
printf("the result is %d\n", (src & mask) == (dest & mask)); //数值运算
 
printf("ths string result is %d\n", (_atoi64(szSrc) & _atoi64(szMask)) ==
 
(_atoi64(szDest) & _atoi64(szMask))); //字符串运算
 
return 0;
 
}
 

运行结果如图:

_atoi64结果

_atoi64结果

总结:

这个坑属于主观想当然型的坑,一定注意确保自己使用的每一个函数都至少仔细地看过一次说明文档。

此条目发表在未分类分类目录。将固定链接加入收藏夹。