第一章 编译预处理

                课程目标

了解嵌入式C语言编程特点和操作细节 结合嵌入式环境深入理解指针、数组和函数 提高编程实践和编程程序规范理解 熟悉C语言标准库应用和特点

 

                   课程结构图

            第一章

第一章

编译预处理与位运算

编译预处理与位运算

 

                                            本章目标

本章概述

讲述宏定义的标准用法和位操作的基本应用

了解预编译的概念,掌握宏定义的方法。

了解“文件包含”与预处理的应用。 了解条件编译的几种形式。

本章目标

了解一些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

转载于:https://www.cnblogs.com/askDing/p/5443585.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值