嵌入式系统编程建立在特定的硬件平台上,要求编程语言具备较强的直接操作硬件能力。C语言作为一种“高级的低级”语言,成为嵌入式系统开发的最佳选择。
8.用#define声明一个常数,用以表明一年中有多少秒
#define SECONDS_PER_YEAR (60*60*24*365)UL
这个表达式使16位机的整型数溢出,因此需要用长整型符号L告诉编译器这个常数是长整型数。如果在表达式中用到UL(表示无符号长整型)。
如何使用C编写死循环?
第一个方案:
while(1){}
第二个方案:
for(;;){}
第三个方案:
Loop:
...
goto Loop;
10.如何访问特定位置的内存
嵌入式系统经常要求程序员去访问特定的内存位置。在某工程中,一个整型变量的绝对地址0x67a9,请将其值设为0xaa55,并且已知编译器是一个纯粹的ANSI编译器,编写代码:
int *ptr;
ptr=(int*)0x67a9;
*ptr=0xaa55;
也可以用以下方法:
*(int *const)(0x67a9)=0xaa55;
对中断服务代码的评论
中断时嵌入式系统中重要组成部分,因此很多编译器开发商都提供使标准C支持中断的扩展。从而产生了一个新的关键字__interrupt。下面代码就使用__interrupt关键字定义中断服务子程序(ISR),请评论一下这段代码优劣:
__interrupt double compute_area(double radius){
double area=PI*radius*radius;
printf("Area = %f",area);
return area;
}
1.ISR不能返回一个值;
2.ISR不能传递参数;
3.在许多的处理器或编译器中,浮点数一般都是不可重入。有些处理器或编译器需要使用额外的寄存器入栈。有些处理器或编译器是不允许在ISR中做浮点运算。此外,ISR应该是短且有效率的,在ISR中浮点运算是不明智的;
4.printf()经常出现重入和性能上的问题;
12.分析代码写结果–整数的自动转换
#include <stdio.h>
#include <stdlib.h>
int main(){
unsigned int a=6;
int b=-20;
if(a+b>6)
printf(">6\n"); //输出>6
else
printf("<=6\n");
printf("%d\n",a+b); //输出-14
system("pause");
}
答案是输出“>6”,原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。为了方便解释,假设int是一个字节:
-20+6=-14,-14的二进制表示为1000 1100,最高一位为符号位。
反码为:1111 0011
补码为:1111 0100
在比较的时候-14的补码被解释为无符号的整数,大于6。
13.关键字static的作用是什么?
1.在函数体,被声明为静态的变量在这一函数被调用的过程中维持其值不变。
2.在模块内(但在函数体外),被声明为静态的变量可以被模块内所有函数访问,但不能被模块外其他函数访问。它是一个本地的全局变量。
3.在模块内,一个被声明为静态的函数只可被这一模块内的其他函数调用。即这个函数被限制在本地范围内。
14.关键字volatile有什么含义?
volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。
用volatile关键字声明的变量i每一次被访问时,执行部件都会从i相应的内存单元中取出i的值。没有用volatile关键字声明的变量i在被访问的时候可能直接从cpu的寄存器中取值(因为之前i被访问过,也就是说之前就从内存中取出i的值保存到某个寄存器中),之所以直接从寄存器中取值,而不去内存中取值,是因为编译器优化代码的结果(访问cpu寄存器比访问ram快的多)。
以上两种情况的区别在于被编译成汇编代码之后,两者是不一样的。之所以这样做是因为变量i可能会经常变化,保证对特殊地址的稳定访问。
15.判断处理器使用Big_endian(大端格式)还是Little_endian(小端格式)存储数据。
编写一个函数,若处理器使用大端格式存储数据,则返回0;若是用小端格式则返回1。
int checkCPU(){
union w{
int a;
char b;
}c;
c.a=1;
return (c.b==1);
}
16.评价代码片段–处理器字长
unsigend int zeros=0;
unsigend int compzeros=0xFFFF;
对于int型不是16位的处理器来说,上面代码是不正确的,应编写如下:
unsigned int compzeros=~0;