课程目标git
了解嵌入式C语言编程特色和操做细节 结合嵌入式环境深刻理解指针、数组和函数 提升编程实践和编程程序规范理解 熟悉C语言标准库应用和特色github
课程结构图express
第一章编程
第一章数组
编译预处理与位运算数据结构
编译预处理与位运算函数
本章目标3d
本章概述指针
讲述宏定义的标准用法和位操做的基本应用调试
了解预编译的概念,掌握宏定义的方法。
了解“文件包含”与预处理的应用。 了解条件编译的几种形式。
本章目标
了解一些C语言特殊的宏定义 重点
宏定义操做
本章结构
编译预处理和位运算
编译预处理和位运算 文件包含
编译预处理 编译预处理
宏定义 宏定义
文件包含
条件编译 条件编译
预处理其余关键词
预处理其余关键词
1 编译预处理与位运算
编译预处理
宏定义
文件包含
条件编译
位运算
其余预处理关键字
1.1编译预处理 做用:对源程序编译以前作一些处理,生成扩展C源程序
种类
格式:
#define #ifdef #ifndef #include #if--#else--#endif等
宏定义
文件包含
条件编译
其余宏定义 #line #error #pragma
“#”开头 占单独书写行 语句尾不加分号
1.2 宏定义
#undef 无参数宏定义 有参数宏定义
1.2.1 #undef #undef定义指令删除前面定义的宏名字。
表达通常形式为:
例子
#undef macro-name
#define MICRO 1 #undef MICRO
1.2.2 无参数宏定义
宏体可缺省,表示宏名 定义过或取消宏体
不带参数宏定义
通常形式: #define 宏名 [宏体] 功能:用指定标识符(宏名)代替字符序列(宏体)
如 #define YES 1
#define NO 0
#define PI 3.1415926
#define OUT printf(“Hello,World”);
例例#d#edfienfeineWWIDITDHTH8080 ()
#d#edfienfeineLELNEGNTGHTHWWIDITDHT+H4+040 v a v r =a r L = E L NE GN TG HT * H2 * ; 2 ;
if(x==YES) printf(“correct!\n”); ()
如
展开例后:#deifi(nxe==1P)I 3.14p1r5in9tf(“correct!\n”);
宏宏展展开开::vavr=ar8=0+8400+4*02;*2;
else if (x==NO) printf(“error!\n”);
prinetfl(s“e2*iPf (Ix==%=f0\n)”,PIp*r2in);tf(“error!\n”); 例 #define MAX MAX+10 (×)
宏展开:printf(“2*PI=%f\n”,3.14159*2); 嵌入式家园 www.embedclub.com
上海嵌入式家园-开发板商城 http://embedclub.taobao.com/
1.2.2 不带参数宏定义 宏定义的规则
宏名通常习惯用大写字母表示,以便与变量名相区别 宏定义不是C语句,没必要在行末加分号 在进行宏定义时,能够引用已定义的宏名,能够层层替换。 只做字符替换,不分配内存空间。
#define R 3.0
#define PI 3.1415926 结果:
#define L 2*PI*R #define S PI*R*R main()
{
L = 18.849556
}
嵌入式家园 www.embedclub.comprintf(“L=%f\nS=%f\n”,L,S);
上海嵌入式家园-开发板商城 http://embedclub.taobao.com/
结果:
L = 18.849556
S = 28.274333
S = 28.274333
1.2.2 不带参数宏定义 宏定义的特色
宏名通常习惯用大写字母表示 提升程序的通用性 宏名的有效范围为定义命令以后到本源文件结束 能够用#undef命令终止宏定义的做用域 宏定义只做简单的替换,不做正确性检查
1.2.2 不带参数宏定义 练习:
定义一个宏,用于计算一年当中的秒数。定义一
个宏,用于计算一年当中的秒数。
1.2.3 带参数宏定义
通常形式: #define 宏名(参数表) 宏体
例 #define S(a,b) a*b ...........
不能加空格
area=S(3,2); 宏展开: area=3*2;
宏展开:形参用实参换,其它字符保留
宏体及各形参之间应加空格
注意宏体的括号
例 #define S (r) PI*r*r
例 #define POWER(x) x*x
至关于定义了不带参宏S,表明字符串“(r) PI*r*r” x=4; y=6;
z=POWER(x+y);
宏展开:z=x+y*x+y;
通常写成: #define POWER(x) ((x)*(x))
宏展开: z=((x+y)*(x+y)); 嵌入式家园 www.embedclub.com
上海嵌入式家园-开发板商城 http://embedclub.taobao.com/
1.2.3 带参数宏定义 带参数宏定义的特色
带参宏定义中,宏名和形参表之间不能有空格出现
例如: #define MAX(a,b) (a>b)?a:b
写为: #define MAX (a,b) (a>b)?a:b 将被认为是无参宏定义,宏名MAX表明字符串 (a,b)(a>b)?a:b
在带参宏定义中,形式参数不分配内存单元,所以没必要做类型定义
在宏定义中的形参是标识符,而宏调用中的实参能够是表达式
#define SQ(y) (y)*(y) main()
{
int a,sq;
printf("input a number: ");
scanf("%d",&a);
sq=SQ(a+1);
printf("sq=%d\n",sq);
在宏定义中,字符串内的形参一般要用括号括起来以免出错
}
1.2.3 带参数宏定义 带参的宏和带参函数很类似,但有本质上的不一样
带参宏 处理时间 编译时
函数 程序运行时
参数类型 处理过程
无类型问题
定义实参,形参类型 分配内存
不分配内存
简单的字符置换
先求实参值,再代入形参 不变
变长 运行速度 不占运行时间
程序长度
调用和返回占时间
1.2.3 带参数宏定义 带参的宏和带参函数很类似,但有本质上的不一样
函数例 宏定义例
main() {
#define SQ(y) ((y)*(y))
int i=1;
while(i<=5) printf("%d\n",SQ(i++));
main() {
}
SQ(int y) {
int i=1; while(i<=5)
return((y)*(y)); }
printf("%d\n",SQ(i++)); }
1.3 文件包含 功能:一个源文件可将另外一个源文件的内容所有包含进来
函数例
#include “file2.c” A
file2.c
嵌入式家园 www.embedclub.com
<> 直接按标准目录搜索
“” 先在当前目录搜索,再搜索标准目录 通常形式: #include “文件名”
或 #include <文件名> 处理过程:预编译时,用被包含文件的内容取代该预处理命令,再对“包
含”后的文件做一个源文件编译
上海嵌入式家园-开发板商城 http://embedclub.taobao.com/
B
A file1.c file1.c
file2.c
1.3 文件包含
被包含文件内容 源文件(*.c) 头文件(*.h)
file3.h
文件包含可嵌套
file1.c A
#include “file2.h”
#include “file3.h”
AB file1.c file2.h
file3.h
宏定义
数据结构定义
函数说明等
file2.h
C
1.3 文件包含 例子
/* powers.h */
#define sqr(x) ((x)*(x))
#define cube(x) ((x)*(x)*(x)) #define quad(x) ((x)*(x)*(x)*(x))
#include <stdio.h>
#include "powers.h"
#define MAX_POWER 10 int main()
{ intn;
}
printf("%2d\t %3d\t %4d\t %5d\n",n,sqr(n),cube(n),quad(n)); 嵌入式家园 www.embedclub.com
printf("number\t exp2\t exp3\t exp4\n"); printf("----\t----\t-----\t------\n"); for(n=1;n<=MAX_POWER;n++)
上海嵌入式家园-开发板商城 http://embedclub.taobao.com/
1.3 文件包含 文件包含特色
一个include命令只能指定一个被包含文件
能够用双引号括起来,也能够用尖括号括起来。
文件包含容许嵌套
被包含文件(file2.h)与其所在的文件(file.c)在预编译以后已成为同一个文 件
1.4 条件编译 #if、#else、#elif #endif
#ifdef和#ifndef
1.4.1 #if、#else、#elif #endif 条件编译指令中最经常使用的或许是#if,#else,#elif和#endif
#if的通常形式是:
#if constant-expression Statement sequence
#endif
#endif标记#if块的结束 例子:
#ifdef COMPUTER_A #define INTEGER_SIZE 16
#else
# define INTEGER_SIZE 32
#endif
1.4.1 #if、#else、#elif #endif 条件编译指令中最经常使用的或许是#if,#else,#elif和#endif
#if的通常形式是:
#if constant-expression Statement sequence
#endif
#endif标记#if块的结束 例子:
#ifdef COMPUTER_A #define INTEGER_SIZE 16
#else
# define INTEGER_SIZE 32
#endif
1.4.1 #if、#else、#elif #endif #else指令的做用与C语言的else类似,#if指令失败时它可
以做为备选指令
#else既是标记#if块的结束,也标记#else块的开始
每一个#if只能写一个#endif匹配
例子:
#include <stdio.h> #define MAX 100 int main(void)
{
}
#if MAX>99
printf(“Compiled for array greater than 99.\n”);
#else
printf(“Complied for small array.\n”);
#endif return 0;
1.4.1 #if、#else、#elif #endif
#elif指令的意思是“不然,若是”
语法格式:
#if expression Statement sequence
#elif expression1 Statement sequence
#elif expression2 ......
#elif expression Statement sequence
#endif
1.4.2 #ifdef和#ifndef #ifdef --若是已定义
#ifdef的通常形式以下: #ifdef 标识符
程序段1 #else
程序段2 #endif
当所指定的标识符已经被#define命令定义过,则在程序编译阶段只编译 程序段1,不然编译程序段2。
1.4.2 #ifdef和#ifndef #ifndef --若是已定义
#ifdef的通常形式以下: #ifndef 标识符
程序段1 #else
程序段2 #endif
做用是当所指定的标识符未被#define命令定义过,则在程序编译阶段只 编译程序段1,不然编译程序段2。它只是第一行与第一种形式不一样。这 种形式与第一种形式的做用相反#ifndef
1.4.2 #ifdef和#ifndef #ifdef和#ifndef
#inlucde <stdio.h> #define T 10
int main(void)
{
#ifdef T
printf(“Hi T\n”);
#else
printf(“Hi anyone\n”);
#endif #ifndef M
printf(“M Not Defined\n”); #endif
return 0; }
1.4.2 #ifdef和#ifndef #if --若是已定义
#if 的通常形式以下: #if 常量表达式
程序段1 #else
程序段2 #endif
如常量表达式的值为真(非0),则对程序段1 进行编译,不然对程序段2进 行编译
1.4.2 #ifdef和#ifndef #if 例子
#define R 1 main()
{
}
float c,r,s;
printf ("input a number: "); scanf("%f",&c);
#if R
r=3.14159*c*c;
printf("area of round is: %f\n",r); #else
s=c*c;
printf("area of square is: %f\n",s); #endif
阶段小节
宏定义的特色和宏定义的取消 带参数宏定义要注意的几个细节
条件编译主要应用在那几个方面,它有几种使用方法 Include 包含文件的两种方法和他们之间的区别特色
1.5 其余预处理关键字
#error 使用defined #line #pragma
#和## 预约义宏
1.5.1 #error
#error指令强制编译程序中止编译
主要用于程序调试
#error指令的通常形式是 #error error-message
注意:
宏串error-message不用双引号包围 能够自定义错误内容
1.5.2 使用defined 肯定是否认义宏名字的方法
defined操做符的通常形式如 defined macro-name
肯定宏MY是否认义:define与#ifdef: #if defined MY
或
#ifdef MY
感叹号”!”来反转相应的条件 #if !defined DEBUG
#endif
printf(“Final Version!\n”);
1.5.3 #line
#line指令改变__LINE__和__FILE__的内容 #line的通常形式
#line number “filename” 主要用于调试和特殊应用
1.5.4 #和## 操做符#一般称为字符串化的操做符
#include <stdio.h> #define mkstr(s) #s int main(void)
{
}
printf(mkstr(I like C)); return 0;
预处理程序把如下的语句:
变成
printf(mkstr(I like C));
printf(“I like C”);
1.5.5 #和## “##”能够把两个独立的字符串链接成一个字符串
#include<stdio.h>
#define SORT(X) sort_function # # X int main(void)
}
{
结果:
结果:
char *array;
int elements,element_size;.
SORT(3) (array,elements,element_size);
SORT(3) 转化为sort_function3 SORT(3) 转化为sort_function3
SORT(3) (array,elements,element_size)转化为 SORT(3) (array,elements,element_size)转化为
sort_function3(array,elements,element_size sort_function3(array,elements,element_size
若是在运行时才能肯定要调用哪一个函数,能够利用 “##”运算符动态地构造要调用函数的名称。
1.5.6 预约义宏
__DATE__ 进行预处理的日期(“Mmm dd yyyy”形
式的字符串文字)
__FILE__ 表明当前源代码文件名的字符串文字 __LINE__ 表明当前源代码中的行号的整数常量 __TIME__ 源文件编译时间,格式微“hh:mm:ss” __func__ 当前所在函数名
1.5.7 预约义宏 例子
#include <stdio.h> #include <stdlib.h> void why_me();
int main()
void why_me() {
{
printf( "The file is %s.\n", __FILE__ ); printf( "The date is %s.\n", __DATE__ ); printf( "The time is %s.\n", __TIME__ ); printf( "This is line %d.\n", __LINE__ ); printf( "This function is %s.\n",
printf( "This function is %s\n", __func__ ); printf( "The file is %s.\n", __FILE__ ); printf( "This is line %d.\n", __LINE__ );
__func__ ); why_me(); return 0;
}
}
阶段小节
位操做几个运算操做的特色 位段的特色和位段数据的引用
位段使用的规则
C语言扩展宏定义几个具体应用
调试
##与# #define
本章结构
编译预处理和位运算
编译预处理和位运算
文件包含 文件包含
讲述条件编译的三种应用方式
和主要功能实现
编译预处理 编译预处理
#define定义的原则和注意事项 及应用
宏定义 宏定义
条件编译 条件编译
预处理其余关键词
预处理其余关键词
预处理的基础操做方式
讲述文件包含的特色和用处, 以及#include””和<>的区别
讲述了#error以及#pragma和 调试输入基本应用
本章总结
宏定义特色和注意细节 条件编译特色和主要用处 文件包含的路径查询规则 C语言扩展宏定义的用法
实验1 题目
用宏定义来实现两个数取最大值
注意事项
?运算符的运用 对参数的包含 define的语法特色
实验结果
掌握宏定义的具体应用,深化对宏定义的操做。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git