目录
三、关键字(volatile、static、const、Union、#define)
一、编译、宏定义
1、高级语言源程序生成机器代码的过程
预处理 ——> 编译 ——> 汇编 ——> 链接
预处理:#define的宏定义、#include的文件包含、#ifdef/#ifndef, #endif, #if/#else的条件编译。
编译:将代码转化为汇编代码
汇编:将汇编代码转化为目标文件(二进制文件)
链接:将目标文件转换为可执行文件
2、linux环境下的开发板执行
1、交叉编译:arm-linux-gcc Hello.c -o Hello(直接转换为可执行文件)
2、修改属性:chmod 111 Hello(111表示可执行,777表示可读写可执行)
3、执行可执行文件:./Hello
3、#include <file.h>
与 #include “file.h”
的区别?
1、
#include <file.h>
直接从编译器自带的函数库中寻找文件;
2、#include “file.h”先从自定义的文件中找,如果找不到再从函数库中寻找文件
。
4、.h头文件中的ifndef/define/endif 的作用?
防止该头文件被重复利用
5、宏定义的应用
(1)用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)(ul:无符号长整型)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
(2)交换两个参数值的“标准”宏.
#define SWAP(a,b) (a)=(a)+(b); (b)=(a)-(b); (a)=(a)-(b)
(3)写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。
#define MIN(A, B) ((A)>=(B)) ? (B) : (A)
(4)已知一个数组table,用一个宏定义,求出数据的元素个数
#define NTBL(tab) (sizeof(tab) / sizeof(tab[0]))
6、嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置 a 的 bit3,第二个清除 a 的bit3。在以上两个操作中,要保持其它位不变。
#define BITS_SET(v) v|=(0x01<<3)
#define BITS_CLR(v) v&=~(0x01<<3)
7、C语言中的死循环
while(1) //方案1
{
;
}
for( ;1 ;) //方案2
{
;
}
Loop:
…
goto Loop; //方案3
8、不能做 switch()
的参数类型
答:实型(即带小数的都不行)
9、带参的宏的有优缺点
(1)优点:不存在类型转换和运算问题,只是替换,不占运行时间
(2)缺点:程序增多,占编译时间
10、带参函数
(1)优点:程序减少,不占编译时间
(2)缺点:存在类型转换和运算问题,占用占运行时间
11、typedef,#define 定义数据类型,两者有什么不同?哪一种更好一点?
#define在预编译的时候做简单的字符替换处理。
typedef是在编译的时候进行的处理,并不是做简单的字符替换,而是同定义一个变量一样声明一个数据类型,然后用它去定义这种数据类型的变量。
typedef char* pStr1;
#define pStr2 char*
pStr1 s1, s2;
pStr2 s3, s4;
在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。上例中define语句必须写成 pStr2 s3, *s4; 这这样才能正常执行。
二、数组与指针
1、定义变量
a)一个整型数 //int a;
b) 一个指向整型数的指针 //int *a;
c) 一个指向指针的的指针,它指向的指针是指向一个整型数 //int **a;
d) 一个有10个整型数的数组 //int a[10];
e) 一个有10个指针的数组,该指针是指向一个整型数的 // int *a[10];
f) 一个指向有10个整型数数组的指针 // int *a[10];
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数 //int (*a)(int );
h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数 //int (*a[10])(int );
2、指针常量和常量指针的区别
const c=10,则不能对c修改
指针常量:int* const p2 = &a;const修饰p2(指针,指针的指向位置不能改变
常量指针:const int *p3,const修饰int(整型变量),不能对值进行修改,
指针常量
char* const p = "hello"; //指针常量
p[0] = 'X'; //正确! 允许修改字符串, 因为该字符串不是常量
p = p2; //错误! 指针是常量, 不许修改p的指向
常量指针
const char* p = "hello"; //指向 "字符串常量"
p[0] = 'X'; //错误! 想要修改字符串的第一个字符. 但是常量不允许修改
p = p2; //正确! 让p指向另外一个指针.
3、什么叫野指针产生的原因,如何规避
答:野指针就是 指针指向的位置是不可知的。
原因:
1、指针变量未初始化
2、指针释放后之后未置空(指针所指向的变量 在指针之前被销毁)
3、指针操作超越变量作用域
规避:
1、初始化时置 NULL
2、释放时置 NULL
4、数组和指针的区别
数组:在静态存储区被创建(如全局数组),或在栈上被创建。
指针:可以随时指向任意类型的内存块。
5、引用和指针有什么区别?
(1)引用必须初始化,指针不必;
(2)引用处初始化后不能改变,指针可以被改变;
(3)不存在指向空值的引用,但存在指向空值的指针;
6、char* s="AAA"; printf("%s",s); s[0]='B'; printf("%s",s); 有什么错?
"AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。 cosnt char* s="AAA"; 然后又因为是常量,所以对是s[0]的赋值操作是不合法的。
三、关键字(volatile、static、const、Union、#define)
1、关键字volatile有什么含义?给出三个不同的例子
(1)防止变量被编译器优化。
(2)被volatile修饰的变量,编译器不会去假设该变量的值
(3)当优化器每次用到该变量的值时,都会去变量的原始地址去读取这个变量的值,而不是使用保存在寄存器中的备份值。
例子:
(1)并行设备的硬件寄存器。
(2)一个中断服务子程序中的非自动变量。
(3)多线程应用中被几个线程任务共享的变量。
2、关键字static的作用是什么?(在C语言和c++的作用)
在C语言中
(1)修饰函数、全局变量时,只能在本文件内使用(2)修饰局部变量时,该变量生命周期延长到程序结束。如果没有被初始化,默认为0,若已被初始化,则只能初始化一次。
在C++中
(1)被static修饰的成员变量在本质上是全局变量,所以需要在类的外部进行定义。
(2)被static修饰的成员函数没有this指针,可以通过类名::函数名进行调用
3、static全局变量、局部变量、函数与普通的全局变量、局部变量、函数有什么区别?
(1)全局变量:static修饰只能初使化一次,且不能在其他文件单元中被引用;
(2)局部变量: static修饰只能初始化一次,下一次依据上一次结果值,生命周期从程序开始到程序结束。
(3)函数:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
4、关键字const有什么含意?
(1)可以定义const常量
(2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
5、Union与struct的区别。(故而常用struct)
1.在存储多个成员信息时,编译器会自动给struct每个成员分配存储空间,struct 可以存储多个成员信息,而Union每个成员会用同一个存储空间,只能存储最后一个成员的信息。
2.都是由多个不同的数据类型成员组成,但在任何同一时刻,Union只存放了一个被先选中的成员,而结构体的所有成员都存在。
3.对于Union的不同成员赋值,将会对其他成员重写,原来成员的值就不存在了,而对于struct 的不同成员赋值 是互不影响的。
6、请说出const与#define 相比,有何优点?(故而常用const)
1、const定义的是只读变量,#define为宏替换
2、const不会改变变量的存储位置,#define定义的宏存储在代码段
3、const 常量有数据类型,而宏常量没有数据类型。
4、编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
7、定义宏时需要注意什么?
(1) 在定义#define 命令时,注意<宏名>和<字符串>之间用空格分开,而不是用等号连接。
(2) 使用#define定义的标识符不是变量,它只用作宏替换,因此不占有内存。
(3) 习惯上用大写字母表示<宏名>。
(4) 定义宏函数时不能有数据类型。
四、C语言的存储空间
静态区也叫做bss段,常量区也叫做初始化数据区域
1.程序的内存分配答:
1)栈区(stack)----由编译器自动分配释放,存放函数的参数值,局部变量等。
2)堆区(heap)----一般由程序员分配释放。分配使用new和malloc,释放使用deleted和free3)全局区(静态区)(static)----全局变量和静态娈量是存放在一块的。初始化的在一块区域,未初始化存放在另一块区域(BSS)。
4)常量区----存放常量字符串。
5)程序代码区----存放函数体的二进制代码。
1.全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
1)全局变量储存在静态数据区,局部变量在堆栈中。
2)全局变量的作用域是整个函数,局部变量的作用域是声明该变量的函数
⒉局部变量能否和全局变量重名?
能,局部会屏蔽全局。要用全局变量,需要使用"::"
3.全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
可以,在不同的C文件中以static形式来声明同名全局变量。只能有一个C文件中对此变量赋初值,此时连接不会出错。
4.如何引用一个已经定义过的全局变量?
用extern关键字在头文件中声明全局变量。
5、堆和栈的区别
Heap是堆,Stack是栈。
(1)栈的空间由操作系统自动分配和回收,而堆上的空间由程序员申请和释放。
(2)栈的空间大小较小,而堆的空间较大。
(3)栈的地址空间往低地址方向生长,而堆向高地址方向生长。
(4)栈的存取效率更高。程序在编译期间对变量和函数的内存分配都在栈上,
且程序运行过程中对函数调用中参数的内存分配也是在栈上。
五、字节
1、32位机器和64位机器
2、char和unsigned char的区别
char能表示-128~127, unsigned char没有符号位,因此能表示0~255