预处理命令

使用预处理命令#define 声明一个常数,用以表明一年有多少秒

  1. 一般来说宏名大写,小写也不报错,但是要大写
  2. 预处理器将为你计算常数表达式的值,不要算出来,直接写式子更清晰
  3. 加括号防止出错
  4. 大小不要超范围加个UL表示 unsigned long
define SECOND_OF_YEAR (365243600)UL

变量定义

用变量a给出下面定义

  1. 一个整型数(An integer) int a;
  2. 一个指向整型数的指针(A pointer to an integer) int *a;
  3. 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer); int **a;
  4. 一个有10个整型数的数组(An array of 10 integers) int a[10];
  5. 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers) int *a[10];
  6. 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers) int (*a)[10];
  7. 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer) int (*a)(int)
  8. 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数(An array of ten pointers to functions that take an integer argument and return an integer) int (*a[10]) (int)

修饰符

下面修饰符的作用是什么

auto

默认情况下都是auto,分配的内存可读可写 如果在{}里面,则分配在栈空间

register

限制变量定义在寄存器上的修饰符 register int a; 编译器尽量安排CPU的寄存器存放a,如果寄存器不足,依然放在内存中 &符号对register型变量不起作用

static

  1. 修饰局部变量 默认局部变量存在于栈空间,生存期短; 加上ststic就局部静态化,局部变量存在于静态数据段保存,生存期长
  2. 修饰全局变量 防止重命名,加上static则作用于只在本文件.c内。
  3. 修饰全局函数 防止重命名,限制该函数只在本文件中使用

const

  • C:“只读”,建议性,不具备强制性,不是常量,还是变量,尽量保持不变,可通过指针修改
  • C++:常量,不能修改 合理地使用可使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。可以减少bug的出现。

volatile

告知编译器编译方法的关键字,不优化编译 一个定义为volatile的变量是说这变量可能会被意想不到地改变,优化器在用到这个变量时必须每次都重新读取这个变量的值,而不是使用保存在寄存器里的备份。

位操作

嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。

unsigned int a;//0100101011
a |= 0x1<<3;
a &= ~0x1<<3;

内存修改

嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。

int *p = (int *)0x67a9;
p[0] = 0xaa66; *p=0xaa66;
//或者
*((int*)0x67a9)=0xaa66;

自动转换

下面的代码输出是什么,为什么?

void foo(void)
{
  unsigned int a = 6;
  int b = -20;
  (a+b > 6) ? puts("> 6") : puts("<= 6");
}

当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数

malloc

malloc(0)可以返回一个有效地址

typedef 和 define

下面哪个好?

#define dPS struct s * 
typedef struct s * tPS;

typedef 好

dPS p1,p2;
tPS p3,p4;

这种情况下,typedef可以初始化两个,define则简单替换无法初始化后面的

a++ ++a

int x=3;
int t;
t = (x++)+(++x);
//---3 + 5
//t=8

x++首先取值3,然后自增为4,++x,首先自增为5,然后取值5,最后3+5=8 对于顺序如下

int a = 5,b = 7,c;
c=a+++b;
//c=12,a++作为整体+b

中断

中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准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()经常有重入和性能上的问题。