【1】用#define声明一个常数,用以表示一年中有多少秒
#define SECONDS_PER_YEAR (60*60*24*365)UL
说明:首先,末尾#define语法末尾不能有分号;
其次,计算式最好带括号;
第三,这个表达式会使16位机的整型数溢出,因此需要用长整型符号L告诉编译器这个常数是长整型数,末尾用UL(无符号长整型)。
【2】用C编写死循环
第一种方案:while(1){}
第二种方案:for(;;){}
第三种方案:Loop:
...
goto Loop; //这种方案是用汇编写的
【3】访问特定内存位置:
在某工程中,一个整型变量的绝对地址是0x67a9,请将其设置为0xaa55,并且已知编译器是一个纯粹的ANSI编译器,请编写代码
int* ptr;
ptr=(int*)0x67a9;
*ptr=0xaa55;
【4】对中断服务代码的评论
以上程序有如下几个错误:
1、ISR不能返回一个值;
2、ISR不能传递参数,即不能有形参;
3、在许多处理器或编译器中,浮点数一般是不可重入的。有些处理器或编译器需要使用额外的寄存器入栈,有些处理器或编译器是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的;
4、printf()经常出现重入和性能上的问题,
【5】对整数自动转换原则的理解
C语言中,整数自动转换原则是:当表达式中同时存在有符号和无符号类型时,所有的操作数都自动转换成无符号类型。因此,上面程序中,第5行,a+b,a是无符号整型,b是有符号整型,二者相加,则b自动转换成无符号整型,-20变成了一个非常大的正整数,那么显然,此时a+b>6是成立的,因此,上面程序最终输出的结果是“>6”。
【6】关键字static的作用
1、在函数体内,局部的stati变量。作用域在函数体内,生存期却为程序的生命周期。一个被声明为静态的变量在这一函数被调用过程中维持其值不变,即本次访问该变量时访问到的是上次调用后的值。因为它被分配在静态存储区内,函数结束调用后并不释放单元,但是在其它的作用域无法访问。当再次访问这个函数时,这个局部的静态变量还存活,因此访问到的是上次调用后的值。
2、在文件模块内(但在函数体外),一个被声明为静态的全局变量,可以被模块内所有函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3、在文件模块内,一个被声明为静态的函数只可以被这个模块内的其它函数调用。即这个函数被限制在声明它的本地范围内。
【7】与全局对象相比,使用静态数据成员有什么优势
1、静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的问题。
2、使用静态数据成员可以隐藏信息,因为静态数据成员可以是private成员,而全局变量不能。
【8】关键字volatile的含义
定义为volatile的变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值。准确地说,优化器在用到volatile变量时必须小心地重新读取该变量的值,而不是使用保存在寄存器里的备份。使用volatile变量的地方如:
1、并行设备的硬件寄存器(如:状态寄存器)。
2、一个中断服务子程序中会访问到的非自动变量。
3、多线程应用中被几个任务共享的变量。
【9】判断处理器使用Big_endian还是Little_endian模式存储数据
编写一个函数,若处理器使用Big_endian模式存数数据,则返回0;若是用Little_endian模式存储数据,则返回1。
分析:首先,应该了解Little_endian和Big_endian模式有所了解,采用Little_endian模式的CPU对操作数的存储方式是从低字节到高字节,而Big_endian模式对操作数的存储方式是从高字节到低字节。
例如,16位数0x1234在Little_endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
0x4000: 0x34
0x4001: 0x12
而在Big_endian模式CPU内存中的存放方式为:
0x4000: 0x12
0x4001: 0x34
32位宽的数0x12345678在Little_endian模式CPU内存中的存放方式为:
0x4000: 0x78
0x4001: 0x56
0x4002: 0x34
0x4003: 0x12
而在Big_endian模式CPU内存中存储方式为:
0x4000: 0x12
0x4001: 0x34
0x4002: 0x56
0x4003: 0x78
该函数为:
在联合体中定义了两个成员int和char,而联合体的大小=sizeof(int)=4,因此该联合体在内存中占4个字节的大小,假设占用的内存地址为:0x1000~0x1003,那么当给a赋值1时,如果按Little_endian方式存放该数据,则:
0x1000: 0x01
0x1001: 0x00
0x1002: 0x00
0x1003: 0x00
那么这个数值1应该存放于地址0x1000中
而联合体有一个特性:成员都从低地址开始存放,所以当c.b=1时,那就证明数值1是存储于地址0x1000中的,那么久可以证明是Little_endian方式存储。
如果按Big_endian方式存放a的数值1,则
0x1000: 0x00
0x1001: 0x00
0x1002: 0x00
0x1003: 0x01
由联合体的特性可知,当以Big_endian方式存储的时候,c.b=0
【10】判断处理器字长
unsigned int CompareZero=~0
cout<<hex<<CompareZero<<endl;
【11】找错(对静态成员与非静态成员的理解)
上面程序中,i为静态成员变量,func2()为静态成员函数
第9行,test(int a):i(1),j(a) {} 根据规定,初始化列表的初始化顺序 应该与 变量声明的顺序一致,而不是按照出现在初始化列表中的顺序,从第7、8行可以看到,变量声明顺序先是i,然后再j,那么在第9行中,也应该先初始化i,再初始化j,那么此时应该i=1,j=a=2,这样看似没有错,但是,忽略了一个细节,i是静态成员变量。
为了与非静态成员变量相区别,i是不能再类的内部被初始化的。
可以在类的外部进行初始化,如,先把第9行改为,test(int a):j(a) {}
然后再在第13行,添加:int test::i=1;
第16行,定义func2函数,首先该函数为静态成员函数,它想访问静态成员变量i,以及普通变量j,但是静态成员函数只能访问静态成员变量,并不能访问非静态成员,因此无法访问j,此行应该改为:
void test::func2() {cout<<i<<endl;}
需要注意的是:
1、静态数据成员必须在类外面初始化,以示与普通数据成员的区别。
2、静态数据成员以及静态函数成员,不属于类的对象,因此没有this指针,也就无法调用类的非静态成员,它是为类的所有的对象所共享。