往期文章:
C规范编辑笔记(一)
C规范编辑笔记(二)
C规范编辑笔记(三)
C规范编辑笔记(四)
C规范编辑笔记(五)
C规范编辑笔记(六)
正文:
大家好,今天来分享一下C语言规范编辑笔记的第七篇,分享这个是希望自己后面忘记了可以去复习一下,同时也希望分享给有需要的小伙伴,所以在每一篇的开头,我都加了以往文章的链接~
好了,话不多说,我们直接来看这期的内容:
1、禁止隐式类型转换。建议使用显式转换,特别是在有符号和无符号类型之间。防止有符号数被转换成无符号数的时候会出错。
如以下案例可以看出:
Bad example:
signed int v1 = -1; //定义v1为有符号整型
unsigned int v2 = 1; //定义v2为无符号整型
if (v1 < v2) //这样比较对将v1隐式转换为无符号,而-1转换为无符号后就为无符号int的最大值,所以这样,v1永远不可能大于v2
{
/* v1转换为无符号int,值-1变为UINT_MAX,因此if条件始终为false */
}
Good example:
signed int v1 = -1;
unsigned int v2 = 1;
if (v1 < (signed int)v2) //通过显示转换,将v2也转换为有符号的
{
/* v2显式转换为有符号整数-条件为true */
}
另外这里需要注意一旦,如果是无符号数用在for循环中,需要注意不能使条件小于0,这样就一直循环下去!!!,如下例子对比:
Bad example:
uint8_t idx;
//以下循环是无限的:idx是无符号的,idx>=0始终为真,因为无符号值不能为负
for(idx = 27; idx >= 0; idx --) {
...
}
Good example:
//有符号整数转换用于避免无限循环
for(idx = 27; (int8_t)idx >= 0; idx --) {
...
}
或者
idx=27;
while (idx >0)
{
...
}
2、建议 - 不要在不同结构的类型上使用指针类型转换。因为这会涉及到自身以外的内存,造成数据错误。如我们通过下述案例可以知道:
Bad example:
#define TAB_SIZE 16U
typedef struct {
int32_t magic;
} s_a; //创建s_a结构体类型
typedef struct {
int32_t magic;
int16_t s;
uint8_t x[TAB_SIZE];
} s_b; //创建s_b结构体类型
void foo(s_a* structa) {
s_b* p = (s_b*)structa; /* 将其转换为位s_b类型 */
p->magic = 0xBAADCAFE;
p->s = 0xDEAD; /* 结构s_a外部溢出 */
p->x[0] = 4; /* 以及数据被覆盖的风险(缓冲区溢出),因为s_a大小小于s_b,所以必然在内存中被转换为s_b类型的s_a会占用后面其他的内存,造成覆盖掉后面的内存的数据!!! */
}
Good_example:
#define TAB_SIZE 16U
typedef struct {
int32_t magic;
} s_a;
typedef struct {
s_a h; //在s_b结构体里面包含s_a结构体,这样后面只用结构体s_b就可以同时也使用s_a结构里面的参数
int16_t s;
uint8_t x[TAB_SIZE];
} s_b;
void foo(s_b* structb) {
structb ->h.magic = 0xCAFEBABE;
structb ->s = 0xBEEF;
structb ->x[0] = 4;
}
从上述两个例子可以对比看出,第一个不好的例子因为将s_a的结构体变量显示转换为s_b结构体类型,造成指针p后面指向的内存空间大小变为了s_b的大小,而超出了s_a本身结构体的范围,所以就会报错,而好的例子中采用包含s_a结构体完美的解决了这个问题。
好了,今天因为两个规范建议用的例子都比较长,所以今天我们就先分享到这里~
我们C规范编辑笔记第八篇见~
本人水平有限,上述信息仅供学习参考,如有错误和不妥之处,请多多指教。
另外创作不易,请勿抄袭,如果有帮助到大家的话希望大家可以点个赞,谢谢~