分析1:volatile 是什么?怎么用?
答:简单的说,就是不让编译器进行优化,即每次读取或者修改值的时候,都必须重新从内
存或者寄存器中读取或者修改,防止从缓存处读取的值是过期了的,所以加了这个volatile
可以保证每次读的值绝对是实时的:
一般说来,volatile 用在如下的几个地方:
1.中断服务程序中修改的供其它程序检测的变量需要加volatile;
2.多任务环境下各任务间共享的标志应该加volatile;
3.存储器映射的硬件寄存器通常也要加volatile 说明,因为每次对它的读写都可能由不同
意义。
我认为这是区分C 程序员和嵌入式系统程序员的最基本的问题。搞嵌入式的家伙们经常
同硬件、中断、RTOS 等等打交道,所有这些都要求用到 volatile 变量。不懂得volatile
的内容将会带来灾难。假设被面试者正确地回答了这是问题(嗯,怀疑是否会是这样),我
将稍微深究一下,看一下这家伙是不是直正懂得volatile 完全的重要性。
分析2:__I、 __O 、__IO 是什么?
答:如下:
__I :输入口。既然是输入,那么寄存器的值就随时会外部修改,那就不能进行优化,每次
都要重新从寄存器中读取。也不能写,即只读,不然就不是输入而是输出了。
__O :输出口,也不能进行优化,不然你连续两次输出相同值,编译器认为没改变,就忽略
了后面那一次输出,假如外部在两次输出中间修改了值,那就影响输出。
__IO:输入输出口,同上。
分析3:为什么加下划线?
答:原因是避免命名冲突,一般宏定义都是大写,但因为这里的字母比较少,所以再添加下
划线来区分。这样一般都可以避免命名冲突问题,因为很少人这样命名,这样命名的人肯定
知道这些是有什么用的。
经常写大工程时,都会发现老是命名冲突,要不是全局变量冲突,要不就是宏定义冲突,所
以我们要尽量避免这些问题,不然出问题了都不知道问题在哪里。
分析4:typedef 是什么意思,怎么使用?
答:typedef 为C 语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型
包括内部数据类型(int,char 等)和自定义的数据类型(struct 等);在编程中使用typedef
目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂
的类型声明。
1) typedef 的最简单使用,例如:typedef long byte_4;表示给已知数据类型long 起个新
名字,叫byte_4
2) typedef 与结构结合使用
例如:typedef struct tagMyStruct
{
int iNum;
long lLength;
} MyStruct;
这语句实际上完成两个操作
操作1:定义一个新的结构类型tagMyStruct, struct 关键字和tagMyStruct 一起,构成
了这个结构类型,不论是否有typedef,这个结构都存在。我们可以用struct tagMyStruct
varName 来定义变量,但要注意,使用tagMyStruct varName 来定义变量是不对的,因为
struct 和tagMyStruct 合在一起才能表示一个结构类型。
struct tagMyStruct
{
int iNum;
long lLength;
};
操作2:typedef 为这个新的结构起了一个名字,叫MyStruct。
typedef struct tagMyStruct MyStruct;
因此,MyStruct 实际上相当于struct tagMyStruct,我们可以使用MyStruct
varName 来定义变量。
分析5:所以具体的typedef 代码解释如下:
1)例:typedef unsigned int uint32_t;
表示使用uint32_t 符号表示unsigned int 符号
2)例:typedef __IO uint32_t vu32;
表示使用vu32 符号表示typedef __IO 符号
3)例:typedef unsigned short int uint16_t;
表示使用uint16_t 符号表示unsigned short int 符号
答:简单的说,就是不让编译器进行优化,即每次读取或者修改值的时候,都必须重新从内
存或者寄存器中读取或者修改,防止从缓存处读取的值是过期了的,所以加了这个volatile
可以保证每次读的值绝对是实时的:
一般说来,volatile 用在如下的几个地方:
1.中断服务程序中修改的供其它程序检测的变量需要加volatile;
2.多任务环境下各任务间共享的标志应该加volatile;
3.存储器映射的硬件寄存器通常也要加volatile 说明,因为每次对它的读写都可能由不同
意义。
我认为这是区分C 程序员和嵌入式系统程序员的最基本的问题。搞嵌入式的家伙们经常
同硬件、中断、RTOS 等等打交道,所有这些都要求用到 volatile 变量。不懂得volatile
的内容将会带来灾难。假设被面试者正确地回答了这是问题(嗯,怀疑是否会是这样),我
将稍微深究一下,看一下这家伙是不是直正懂得volatile 完全的重要性。
分析2:__I、 __O 、__IO 是什么?
答:如下:
__I :输入口。既然是输入,那么寄存器的值就随时会外部修改,那就不能进行优化,每次
都要重新从寄存器中读取。也不能写,即只读,不然就不是输入而是输出了。
__O :输出口,也不能进行优化,不然你连续两次输出相同值,编译器认为没改变,就忽略
了后面那一次输出,假如外部在两次输出中间修改了值,那就影响输出。
__IO:输入输出口,同上。
分析3:为什么加下划线?
答:原因是避免命名冲突,一般宏定义都是大写,但因为这里的字母比较少,所以再添加下
划线来区分。这样一般都可以避免命名冲突问题,因为很少人这样命名,这样命名的人肯定
知道这些是有什么用的。
经常写大工程时,都会发现老是命名冲突,要不是全局变量冲突,要不就是宏定义冲突,所
以我们要尽量避免这些问题,不然出问题了都不知道问题在哪里。
分析4:typedef 是什么意思,怎么使用?
答:typedef 为C 语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型
包括内部数据类型(int,char 等)和自定义的数据类型(struct 等);在编程中使用typedef
目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂
的类型声明。
1) typedef 的最简单使用,例如:typedef long byte_4;表示给已知数据类型long 起个新
名字,叫byte_4
2) typedef 与结构结合使用
例如:typedef struct tagMyStruct
{
int iNum;
long lLength;
} MyStruct;
这语句实际上完成两个操作
操作1:定义一个新的结构类型tagMyStruct, struct 关键字和tagMyStruct 一起,构成
了这个结构类型,不论是否有typedef,这个结构都存在。我们可以用struct tagMyStruct
varName 来定义变量,但要注意,使用tagMyStruct varName 来定义变量是不对的,因为
struct 和tagMyStruct 合在一起才能表示一个结构类型。
struct tagMyStruct
{
int iNum;
long lLength;
};
操作2:typedef 为这个新的结构起了一个名字,叫MyStruct。
typedef struct tagMyStruct MyStruct;
因此,MyStruct 实际上相当于struct tagMyStruct,我们可以使用MyStruct
varName 来定义变量。
分析5:所以具体的typedef 代码解释如下:
1)例:typedef unsigned int uint32_t;
表示使用uint32_t 符号表示unsigned int 符号
2)例:typedef __IO uint32_t vu32;
表示使用vu32 符号表示typedef __IO 符号
3)例:typedef unsigned short int uint16_t;
表示使用uint16_t 符号表示unsigned short int 符号