第二章数据类型

来源:互联网 发布:linux流量监控工具 编辑:程序博客网 时间:2024/06/01 07:40

1.char ch='a';

   int a=(int)ch;

  printf("%d%c\n,a,ch);

ch是什么?ch里面装的是什么?a是什么?a里面装的是什么内容?打印结果是什么?

ch是字符型变量,ch里是a的二进制数,a是整形变量,装的是“a”的二进制数的整形表示方式,结果是97和a。


2.简述局部变量和全局变量的使用方法及区别

1. 作用域不同:全局变量的作用域为整个程序,而局部变量的作用域为当前函数或循环等
2. 内存存储方式不同:全局变量存储在全局数据区中,局部变量存储在栈区
3. 生命期不同:全局变量的生命期和主程序一样,随程序的销毁而销毁,局部变量在函数内部或循环内部,随函数的退出或循环退出就不存在了
4. 使用方式不同:全局变量在声明后程序的各个部分都可以用到,但是局部变量只能在局部使用。函数内部会优先使用局部变量再使用全局变量


3.简述声明与定义的含义和区别

定义:创建一个对象,为该对象分配一块内存并给它取上名字,不可分离,内存位置也不能改变,且一个变量或对象在一定区域内只可定义一次

声明:1.告诉编译器,这个名字已经分配到一块内存上了,声明可出现多次

            2.告诉编译器,改名字已经预订了,其他地方不可以用它作为变量名或对象名。


4.static与extern的使用方法和作用

static修饰变量,其空间在内存中的静态区分配,其生命周期一直持续到整个程序执行结束为止,该变量只在初次运行时进行初始化工作,且仅一次,未进行初始化的,系统自动赋值为0或\0,修饰全局变量时,改变了作用域,由原来的整个工程可见到本源文件可见。

extern:修饰变量和函数,表示该变量或函数在其他地方被定义,在使用其他源文件中定义的变量时,必须使用extern关键字


5.register有何作用,使用方法与注意事项

register修饰变量,该变量会作为一个寄存器变量,访问速度达到最快,即直接引用寄存器,对变量名的操作结果是直接对寄存器进行访问。


6.为什么要使用volatile修饰一些变量

volatile 是在C ,C++,Java等中语言中的一种修饰关键字。
这个关键字在嵌入式系统中,是一个非常重要的一个使用。尽管在一般的Application中,可能很多人都不需要使用这个。但是在单片机中,如果不熟悉这个关键字,很有可能产生想像不到的意外。
那么,我就来谈谈Volatile的意义--


volatile在ANSI C(C89)以后的C标准规格和const一起被包含在内。在标准C中,这些关键字是必定存在的。


关于volatile的意义,根据标准C的定义、


    volatile的目的是,避免进行默认的优化处理.比如说对于编译器优化的功能,如果从编译器看来,有些多余的代码的话,编译器就会启动优化程序,并删除一些代码,但是这在嵌入式系统中很有可能是关键性的处理,必须不能保证被编译器删掉,所以提供了Volitile来声明,告诉编译器无论如何都不要删掉我。


举个例子--
■比如说下面条件的一段代码


extern int event_flag


void poll_event()
{
while (event_flag == 0) {
    /* 不操作event_flag */
    ....
}
....
}


我们不再循环中改变这里的event_flag的值,这样的话,event_flag 看起来就像是多余的,因此单片机编译器可能把此程序看为下段程序


void poll_event()
{
if (event_flag == 0) {
    while (1) {
      /* 不对event_flag操作 */
    ....
    }
}
....
}


对于一般的编译器,一般都会把程序优化成上述程序。优化while循环使其不必每次判断条件
这样的优化确实可以提高代码速度,比如while循环中不再需要对条件的判断,所以很快,但是这是正确的吗?


对于单线程的程序,这是没有问题的,因为event_flag 就永远不会改变,但是对于多线程程序,RTOS的多任务处理的话,event_flag 的值可能被其他线程改变,这样问题就来了,因为被优化的代码并不具备对用event_flag 变化的能力。因此导致错误的意想不到的结果,如果此代码在ECU上执行的话,那我们的小命可就有可能没了。。。。


为了避免这种情况,我们使用volatile关键字来防止程序被编译器优化。具体的使用方法,我们用下面的程序来说明’


extern volatile int event_flag


这样声明event_flag全局变量的话,就不用担心event_flag 被优化掉,程序将按照设计来运行。



7.typedef的主要作用是哪两个

  1.给变量一个新名字

  2.简化较复杂的类型声明

例如:

1.typedef long byte_4

2.typedef struct tag_my_struct

{

 int i_num

}mystruct


8.typedef与#define的区别

1) #define是预处理指令,不会参与编译过程,只是在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。例如: 
#define PI 3.1415926 
程序中的:area=PI*r*r 会替换为3.1415926*r*r 
如果你把#define语句中的数字9 写成字母g 预处理也照样带入。


2)typedef是在编译时处理的。它在自己的作用域内给一个已经存在的类型一个别名,但是You cannot use the typedef specifier inside a function definition。


3)typedef int * int_ptr ; 与#define int_ptr int * 
作用都是用int_ptr代表 int * ,但是二者不同,正如前面所说 ,#define在预处理 时进行简单的替换,而typedef不是简单替换 ,而是采用如同定义变量的方法那样来声明一种类型。也就是说;


#define int_ptr int *
int_ptr a, b; //相当于int * a, b; 只是简单的宏替换


typedef int* int_ptr;
int_ptr a, b; //a, b 都为指向int的指针,typedef为int* 引入了一个新的助记符
1
2
3
4
5
这也说明了为什么下面观点成立


typedef int * pint ; 
#define PINT int *


那么: 
const pint p ;//p不可更改,但p指向的内容可更改 
const PINT p ;//p可更改,但是p指向的内容不可更改。


pint是一种指针类型 const pint p 就是把指针给锁住了 p不可更改 
而const PINT p 是const int * p 锁的是指针p所指的对象。


4)也许您已经注意到#define 不是语句 不要在行末加分号,否则 会连分号一块置换。



9.结构变量与联合变量的长度如何定义

一个结构变量的长度为各成员长度的总和

一个联合变量的长度为各成员中最长的长度


10.枚举与#define宏的主要区别

(1)从处理过程的角度看:


#define宏是由编译预处理器在预编译处理时处理的,而且只做简单的字符串的替换。枚举常量则是在编译的时候确定其值的。


(2)从调试的角度看:


通常情况下,在编译器里,可以调试枚举常量,而不能调试宏常量。


(3)从数据的类型看:


#define可以编译任意类型的常量,而枚举只能是定义整型常量。


(4)从代码编写角度看:


枚举可以一次定义大量常量,而#define宏只能一次定义一个。


(5)从可维护性来看:


枚举可以集中管理数据,具相同属性的整形数据可使用枚举,枚举可实现取值的自增,也可指定每个枚举的值,编写代码跟容易,相对来说能减少出错的机会,也便于代码的后期维护和修改。


(6)枚举的取值范围已经限定了,容易进行参数的检查,而define没有这种检查

原创粉丝点击