C 语言中有些操作符很容易混淆,编码时要非常小心。
赋值操作符“=” 逻辑操作符“==” 关系操作符“<” 位操作符"<<" 位操作符“>>” 关系操作符“>” 位操作符"|" 逻辑操作符“&&” 逻辑操作符"!" 位操作符“~” 2. 2. 易用错的操作符
(1) 除操作符"/"
当除操作符“/”的运算量是整型量时,运算结果也是整型。
如:1/2=0
(2)求余操作符"%"
求余操作符"%"的运算量只能是整型。
如:5%2=1,而 5.0%2 是错误的。
(3)自加、自减操作符“++”、“--”
示例 1
k = 5;
x = k++;
执行后,x = 5,k = 6
示例 2
k = 5;
x = ++k;
执行后,x = 6,k = 6
示例 3
k = 5;
x = k--;
执行后,x = 5,k = 4
示例 4
k = 5;
x = --k;
执行后,x = 4,k = 4
这个原则看似和“面向接口”编程思想相悖,但是实现往往会影响接口,函数所能实现的功能,除了和调用者传递的参数相关,往往还受制于其他隐含约束,如:物理内存的限制,网络状况,具体看“抽象漏洞原则”。
内存操作主要是指对数组、指针、内存地址等的操作。内存操作越界是软件系统主要错误之一,后果往往非常严重,所以当我们进行这些操作时一定要仔细小心。 示例:使用 itoa()将整型数转换为字符串时:
char TempShold[10] ;
itoa(ProcFrecy,TempShold, 10); /* 数据库刷新间隔设为值1073741823时,系统监控后台coredump,
监控前台抛异常。*/
TempShold 是以‘\0’结尾的字符数组,只能存储 9 个字符,而 ProcFrecy 的最大值可达到 10 位,导致符数组 TempShold 越界。
正确写法:一个 int(32 位)在-2147483647 ~ 2147483648 之间,将数组 TempShold 设置成 12 位。
char TempShold[12] ;
itoa(ProcFrecy,TempShold,10);
坚持下列措施可以避免内存越界:
示例:异常出口处没有释放内存
MsgDBDEV = (PDBDevMsg)GetBuff( sizeof( DBDevMsg ), **LINE**);
if (MsgDBDEV == NULL)
{
return;
}
MsgDBAppToLogic = (LPDBSelfMsg)GetBuff( sizeof(DBSelfMsg), **LINE** );
if ( MsgDBAppToLogic == NULL )
{
return; //MsgDB_DEV 指向的内存丢失
}
坚持下列措施可以避免内存泄漏:
示例:一个函数返回的局部自动存储对象的地址,导致引用已经释放的内存空间
int* foobar (void)
{
int local_auto = 100;
return &local_auto;
}
坚持下列措施可以避免引用已经释放的内存空间:
使用变量时要注意其边界值的情况。
示例:如 C 语言中字符型变量,有效值范围为-128 到 127。故以下表达式的计算存在一定风险。
char ch = 127;
int sum = 200;
ch += 1; // 127为ch的边界值,再加将使ch上溢到-128,而不是128
sum += ch; // 故sum的结果不是328,而是72。
有很多函数申请内存,保存在数据结构中,要在申请处加上注释,说明在何处释放。
goto 语句会破坏程序的结构性,所以除非确实需要,最好不使用 goto 语句。 可以利用 goto 语句方面退出多重循环;同一个函数体内部存在大量相同的逻辑但又不方便封装成函数的情况下,譬如反复执行文件操作,对文件操作失败以后的处理部分代码(譬如关闭文件句柄,释放动态申请的内存等等),一般会放在该函数体的最后部分,再需要的地方就 goto 到那里,这样代码反而变得清晰简洁。实际也可以封装成函数或者封装成宏,但是这么做会让代码变得没那么直接明了。 示例:
int foo(void)
{
char* p1 = NULL;
char* p2 = NULL;
char* p3 = NULL;
int result = -1;
p1 = (char *)malloc(0x100);
if (p1 == NULL)
{
goto Exit0;
}
strcpy(p1, "this is p1");
p2 = (char *)malloc(0x100);
if (p2 == NULL)
{
goto Exit0;
}
strcpy(p2, "this is p2");
p3 = (char *)malloc(0x100);
if (p3 == NULL)
{
goto Exit0;
}
strcpy(p3, "this is p3");
result = 0;
Exit0:
free(p1); // C标准规定可以free空指针
free(p2);
free(p3);
return result;
}
示例:如下程序将造成变量下溢。
unsigned char size ;
…
while (size-- >= 0) // 将出现下溢
{
... // program code
}
当 size 等于 0 时,再减不会小于 0,而是 0xFF,故程序是一个死循环。应如下修改。
char size; // 从unsigned char 改为char
…
while (size-- >= 0)
{
... // program code
}