1.枚举与define的区别:
(1)从处理过程的角度看:
#define宏是由编译预处理器在预编译处理时处理的,而且只做简单的字符串的替换。枚举常量则是在编译的时候确定其值的。
(2)从调试的角度看:
通常情况下,在编译器里,可以调试枚举常量,而不能调试宏常量。
(3)从数据的类型看:
#define可以编译任意类型的常量,而枚举只能是定义整型常量。
(4)从代码编写角度看:
枚举可以一次定义大量常量,而#define宏只能一次定义一个。
(5)从可维护性来看:
枚举可以集中管理数据,具相同属性的整形数据可使用枚举,枚举可实现取值的自增,也可指定每个枚举的值,编写代码跟容易,相对来说能减少出错的机会,也便于代码的后期
维护和修改。
(6)枚举的取值范围已经限定了,容易进行参数的检查,而define没有这种检查。
2.volatile关键字:
(1)volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的
时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存
器中的值。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从
该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可
以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile
关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进
行编译优化,以免出错)
(2)使用volatile的几种情形:
<1>中断服务程序中修改的供其它程序检测的变量需要加volatile;
<2>多任务环境下各任务间共享的标志应该加volatile
<3>存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义。
例如:
假设要对一个设备进行初始化,此设备的某一个寄存器为0xff800000。
int *output = (unsigned int *)0xff800000; //定义一个IO端口
int init(void)
{
int i;
for(i=0;i< 10;i++){
*output = i;
}
}
经过编译器优化后,编译器认为前面循环半天都是废话,对最后的结果毫无影响,因为最终只是将output这个指针赋值为9,所以编译器最后给你编译编译的代码结果相当于:
int init(void)
{
*output = 9;
}
如果你对此外部设备进行初始化的过程是必须是像上面代码一样顺序的对其赋值,显然优化过程并不能达到目的。反
之如果你不是对此端口反复写操作,而是反复读操作,其结果是一样的,编译器在优化后,也许你的代码对此地址的
读操作只做了一次。然而从代码角度看是没有任何问题的。这时候就该使用volatile通知 编译器这个变量是一个不稳定
的,在遇到此变量时候不要优化。
另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以
通过关中断来实现,2中禁止任务调度,3中则只能依靠硬件的良好设计。
(3)在这里我们需要注意:频繁地使用volatile很可能会增加代码尺寸和降低性能,因此要合理的使用volatile。