嵌入式c语言——学习笔记2
一、Typedef
typedef 在代码中用得最多的就是定义结构体的类型别名和枚举类型
struct _GPIO
{
__IO uint32_t CRL;
__IO uint32_t CRH;
…
};
定义了一个结构体 GPIO,这样我们定义变量的方式为:
struct _GPIO GPIOA;//定义结构体变量 GPIOA
但是这样很繁琐, MDK 中有很多这样的结构体变量需要定义。这里我们可以为结体定义一个别名 GPIO_TypeDef,这样我们就可以在其他地方通过别名 GPIO_TypeDef 来定义结构体变量了。方法如下:
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
…
} GPIO_TypeDef;
Typedef 为结构体定义一个别名 GPIO_TypeDef,这样我们可以通过 GPIO_TypeDef 来定义结构体变量:
GPIO_TypeDef GPIOA,GPIOB;
这里的 GPIO_TypeDef 就跟 struct _GPIO 是等同的作用了。除了用在结构体上,typedef类型别名也大量用在int、short等这种变量上。
二、结构体
声明结构体类型:
Struct 结构体名{
成员列表;
}变量名列表;
例如:
Struct U_TYPE {
Int BaudRate
Int WordLength;
}usart1,usart2;
在结构体申明的时候可以定义变量,也可以申明之后定义,方法有:Struct 结构体名字 结构体变量列表 ;
例如:
struct U_TYPE usart1,usart2;
结构体成员变量的引用方法是:结构体变量名字.成员名
比如要引用 usart1 的成员 BaudRate,方法有:
usart1.BaudRate;
结构体指针变量定义也是一样的,跟其他变量没有啥区别。
例如:
struct U_TYPE *usart3;//定义结构体指针变量 usart1;
结构体指针成员变量引用方法是通过“->”符号实现,比如要访问 usart3 结构体指针指向的结构体的成员变量 BaudRate,方法有:
Usart3->BaudRate;
使用结构体的好处是防止函数的入口参数过多,当然也利于增加变量时不用修改函数定义,对于一组描述同一对象的参数,用结构体使他们形成一个整体,也有利于代码的可读性,不会使变量定义显得混乱。
三、宏定义
宏定义用法:
1、宏常量:我们最常使用到的#define的用法就是用#define来定义一个符号常量,而要修改时,只需修改#define这条语句就行了,不必每处代码都修改
例如:
#include"stdio.h"
#define PI 3.14
#define STR "圆周率约等于"
int main()
{
printf("%s %f",STR,PI); //预处理时会被替换为 printf("%s %f","圆周率约等于",3.14);
return 0;
}
2、宏语句:我们还可以用宏定义一条或多条语句
例如:
#include"stdio.h"
#define Print printf("hello world!")
int main()
{
Print; //预处理时会被替换为 printf("hello world!");
return 0;
}
3、宏函数:我还可以用宏来定义函数,因为宏定义也可以带参数
例如:
#include"stdio.h"
#define Print(str) printf("%s",str)
int main()
{
Print("这是一个只有一条语句的宏函数!");
//预处理时会被替换为 printf("%s","这是一个只有一条语句的宏函数!")
return 0;
}
运算符优先级问题:
#define SQUARE_SUM(x,y) x*x+y*y
#include <stdio.h>
int main()
{
int i = 1,j = 2,k ;
k = SQUARE_SUM(i+1,j);
printf("%d",k);
return 0;
}
很多人可能会这样算:2*2+2*2=8,这样其实是错误的。原因是程序只是做了替换,也就是1+1*1+1+2*2=7
如果想要结果为8的话应该这样写:
#define SQUARE_SUM(x,y) (x)*(x)+(y)*(y) //注意这里的括号!!
#include <stdio.h>
int main()
{
int i = 1,j = 2,k ;
k = SQUARE_SUM(i+1,j);
printf("%d",k);
return 0;
}
四、条件编译:
条件编译命令最常见的形式为:
#ifdef 标识符
程序段 1
#else
程序段 2
#endif
它的作用是:当标识符已经被定义过(一般是用#define 命令定义),则对程序段 1 进行编译,否则编译程序段 2。 其中#else 部分也可以没有,即:
#ifdef
程序段 1
#endif
条件编译规则如下:
#ifdef MAVIS //如果定义了MAVIS,则执行下面的条件
{
;
}
#else //如果未定义了MAVIS,则执行下面的条件 //#else 可省略
{
;
}
#endif
// 备注: C只编译符合条件的模块;
// 例如:
#ifdef CUSTOMIZED
// thread 0
{
"Dsp1-thread0", // thread name
Alg_init, // init function
Alg_prep, // pre-process function
Alg_proc, // main process function
Alg_deinit, // de-init function
TRUE, // need output buffer?
},
#endif
// thread 1,
{
"",//Dsp1-thread1", // thread name
NULL, // init function
NULL, // pre-process function
NULL, // main process function
NULL, // de-init function
FALSE, // need output buffer
}
运用#if #elif #elif #else #endif 来进行条件编译:
#if defined (IBMPC) //可以用 #if defined(VAX) 代替 #ifndef VAX 和#elif 一起使用;
#include "ibmpc.h"
#elif defined (VAX)
#include "vax.h"
#elif defined (MAC)
#include "mac.h"
#else
#include "general.h"
#endif