1、把小写字母转化成大写字母
int Lower(int c)
{
if(c >= 'A' && c <= 'Z')
{
return c + 'a' - 'A';
}
else
{
return c;
}
}
2、Max宏
#define Max(A,B) ((A) > (B) ? (A) : (B))
3、关于#
#define Dprintf(Expr) printf(#Expr " = %d\n",Expr)
Dprintf(x/y);
展开后
printf("x/y = %d\n",x/y);
#define Paste(Front,Back) Front ## Back
Paste(Name,1);将会建立记号Name1
4、关于void指针
任何类型的指针都可以转换成void指针,并且在奖它转换回原来的类型不会丢失信息。
5、关于int *Fun()和int (*Fun)()两个声明
int *Fun() 是一个函数,返回一个int指针。
int (*Fun)() 是一个函数指针返回一个int类型。
6、关于局部变量和结构体成员的顺序
32位CPU要学会享受,定义成32位变量比定义为8位运算速度快。
如下定义在keil4下浪费RAM,结构体中也是这样,貌似结构体有个关键字,不同的编译器不同名称
Keil4下叫 __packed 使用此关键字,结构体以压缩的方式存放成员,不存在RAM浪费,但是耗费了时间。
void MyFun(void)
{
gUINT32 Temp1; /*这样定义浪费内存*/
gUINT8 Temp2; /*浪费三个字节*/
gUINT32 Temp3;
gUINT8 Temp4; /*浪费三个字节*/
gUINT32 Temp5;
gUINT8 Temp6; /*浪费三个字节*/
/*..........................*/
}
应当这样定义
void MyFun(void)
{
gUINT32 Temp1;
gUINT32 Temp3;
gUINT32 Temp5;
gUINT8 Temp4;
gUINT8 Temp2;
gUINT8 Temp6; /*浪费了一个字节*/
/*..........................*/
}
7、RO、RW、ZI 含义
RO:存放只读代码和常量
RW:存放已经初始化的变量
ZI:存放没有初始化的变量
8、函数参数传递、函数返回值、局部变量 (详见ATPCS文档)
在ARM中
参数传递:使用R0-R3,多于4个使用栈传递。R0第一个参数
返回值: 使用R0-R3,一个字使用R0,两字R0-R1、三个字R0-R2、四个字R0-r3
局部变量:使用R4-R11(ARM)、R4-R7(Thumb),过多的使用栈保存
中断函数中只使用R0-R3,不使用R4-R11,进入中断程序前一定要保存R0-R3等寄存器 (凭自己的推断,貌似在哪里见过不太确定)
Cortex-M3内核进入异常服务例程时,自动压栈了R0-R3,R12,LR(R14,连接寄存器),;PSR(程序状态寄存器)和PC(R15).并且在返回时自动弹出。不用加__irq关键字
这也是推断的理由之一
看到周立功的ARM7 ucos例程也没有保存R4-R11,理由二
9、实时操作系统任务切换的时候为什么要保存R0-R15 (ARM)
R0-R3 保存的当前任务的参数,切换到其他任务可能别修改,当任务切换回来现场以经改变。故必须保存
R4-R11 保存了当前任务中的局部变量,可能被其他任务更改。也必须保存
R12 过程调用中间临时寄存器
R13 栈指针
R14 连接寄存器保存子函数返回的地址
R15 程序PC
10、中断函数没有参数没有返回值
11、函数指针这样定义
uint8_t (* pfnRcvIntHandlerCan1) (CpCanMsg_ts *, _U08);
函数参数只写类型。注意函数指针的括号
12、typedef void (*TmrHandler_fn)(void); //声明
main()
{
TmrHandler_fn fnTmrCall; //定义
......
}
这两句就是定义了一个函数指针: void (*fnTmrCall)(void); //无参数,无返回值
这样做可以使函数指针的定义简单化,类似定义变量,看起来直观
13、
struct McTmrFunc_s //声明结构体
{
uint32_t ulControl;
uint32_t ulTickCurrent;
uint32_t ulTickPeriod;
TmrHandler_fn fnTmrCall;
};
typedef struct McTmrFunc_s McTmrFunc_ts; //起别名
static McTmrFunc_ts atsTmrFuncS[MC_TMR_FUNCTION]; //定义结构体
一下方法可以实现相同功能,并且更简洁。
typedef struct McTmrFunc_s //声明结构体,并起别名
{
uint32_t ulControl;
uint32_t ulTickCurrent;
uint32_t ulTickPeriod;
TmrHandler_fn fnTmrCall;
}McTmrFunc_ts;
static McTmrFunc_ts atsTmrFuncS[MC_TMR_FUNCTION]; //定义结构体
14、返回值是函数指针的函数
typedef int (*pFunc)(int *,int);
pFunc Function(int Par) 定义了一个函数,这个函数的返回值是个函数指针,这个函数指针指向有两个参数且返回值是int型的函数。
{
......
}
15、函数调用另一个函数为了现场保护会导致入栈、出栈、跳转等操作,导致效率降低,某些比较简单的函数,改用宏实现可以提高效率。
当然使用宏的方法将会产生较大程序代码,要注意。
如:两个数比较大小(这是比较简单的例子,还有更复杂的宏函数)
#define MAX(a,b) ((a)>(b)?) (a) : (b)
#define MIN(a,b) ((a)<(b)?) (a) : (b)
16、const关键字
const char *Ptr; //指针指向的内容不能改变 ,即。指向的对象只读。Ptr可以改变
char const *Ptr; //同上
char *const Ptr; //Ptr只读,不能改变指向。
17、头文件的书写加上下面的宏,会避免重复定义等现象出现。
#ifndef _CP_MSG_H_
#define _CP_MSG_H_
......
...... //头文件内容写在这里
......
#endif
18、#error关键字,移植方便。
注:DNS_MSG_COS 和 DNS_CLASS_2B都是宏
#if (DNS_MSG_COS == 0) && (DNS_CLASS_2B == 1)
#error Please disable class 2B for this configuration
#endif
编译时如果条件成立,编译器就会输出error信息Please disable class 2B for this configuration
19、如果编译器是C++编译器,告诉编译器中间是C代码,使用C代码的编译方法编译。
#ifdef __cplusplus
extern "C" {
#endif
......
...... C 代码
......
#ifdef __cplusplus
}
#endif
20、sizeof是个关键字不是个函数,要注意。
21、在Keil4、LPC2129、不使用分散加载文件的环境下。RAM的分配是这样的
LPC2129的RAM地址是0x40000000,大小是0x4000
从0x40000000开始依次存放的是:
已经初始化的全局变量,其后是没有初始化的全局变量(BBS区),然后是堆区,然后是栈区,最后是没有使用的RAM。
+------------------+-----> 0x40000000 RAM开始
| 初始化的全局变量 | DATA区
+------------------+-----> 0x40000184
| 未始化的全局变量 | BBS区
+------------------+-----> 0x40000d18
| 堆 | 这里堆区空间是0
+------------------+-----> 0x40000d18 栈底
| 栈 | 栈区
+------------------+-----> 0x400011a0 栈顶
| 空闲RAM |
+------------------+-----> 0x40004000 RAM结束
一般不使用标准库的内存分配函数的话,堆区可以设置为0,也就是不使用堆。
要注意的是:局部变量存放在栈区,如果局部变量过多超过了栈的大小。因为栈是满递减的会把堆区,甚至全局变量覆盖,导致程序崩溃。
编写程序时一定要注意。