1.1 指针的类型转换
1.1.1 指向不同数据类型的指针之间不能相互转换
考虑下面一段程序:
uint8_t *p1; uint32_t *p2; p2 = (uint32_t *)p1; |
如果CPU允许各种数据对象存放在任意的存储单元,则以上转换没有任何问题。但是有些CPU对某些数据类型加强了对齐限制,要求这些数据类型占用一定的地址空间,比如某些字节寻址的CPU要求32位(4字节)整型存放在4的整数倍地址上。
1.1.2 转换过程中不能丢失指针的const、volatile属性
丢失const属性,将有可能导致在只读内容进行写操作,编译器不会发出警告,编译器将不对具有volatile属性的变量作优化;丢失volatile属性,编译器的优化可能导致程序员预先设计的硬件时序操作失效,这样的错误很难发现。
1.2 指针运算
1.2.1 只有指向数组的指针才能进行算术运算
1.2.2 只有指向同一数组的指针才能进行相减运算
1.2.3 只有指向同一数组的指针才允许用>、>=、<、<=等关系运算符进行比较操作
1.2.4 只允许用数组索引做指针运算
void func(uint8_t *p1, uint8_t p2[]) { uint8_t index = 0; uint8_t *p3; uint8_t *p4;
*p1 = 0; p1++; /* 不允许,p1不是指向数组的指针 */ p1 = p1 + 5; /* 不允许,p1不是指向数组的指针 */ p1[5] = 0; /* 不允许,p1不是指向数组的指针 */ p3 = &p1[5]; /* 不允许,p1不是指向数组的指针 */ p2[0] = 0; index++; index = index + 5; p2[index] = 0; /* 允许 */ *(p2+index) = 0; /* 不允许 */ p4 = &p2[5]; /* 允许 */ } |
1.3 指针的有效性
1.3.1 动态分配的对象不允许在本对象消亡后传给另一个对象
这条规则的实际意义是指不能将栈对象的地址传递给外部作用域的对象。
考虑下面一段程序:
char *getm(uint32_t len) { char *p = (char *)malloc(len*sizeof(char)); return p; }
void main() { char *p = getm(100); …… } |