【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】对中断服务代码的评论

wKioL1Y8z2ixVzXdAACasjDKVUM466.jpg

以上程序有如下几个错误:

1、ISR不能返回一个值;

2、ISR不能传递参数,即不能有形参;

3、在许多处理器或编译器中,浮点数一般是不可重入的。有些处理器或编译器需要使用额外的寄存器入栈,有些处理器或编译器是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的;

4、printf()经常出现重入和性能上的问题,


【5】对整数自动转换原则的理解

wKiom1Y80GbgoLcrAACQpGP2HK0953.jpg

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


该函数为:

wKiom1ZAmjmyfUPtAAAW9gVRFEo193.png

在联合体中定义了两个成员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】找错(对静态成员与非静态成员的理解)

wKioL1ZBpsCjBqMtAAEl7b81tso746.jpg

wKiom1ZBpnmgNK75AAHlwbRhE94387.jpg

上面程序中,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指针,也就无法调用类的非静态成员,它是为类的所有的对象所共享。