




已阅读5页,还剩59页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
嵌入式C语言高级编程篇,课程目标,了解嵌入式C语言编程特点和操作细节 结合嵌入式环境深入理解指针、数组和函数 提高编程实践和编程程序规范理解 熟悉C语言标准库应用和特点,课程结构图,编译预处理与位运算,第1章,本章目标,本章概述 讲述宏定义的标准用法和位操作的基本应用 了解预编译的概念,掌握宏定义的方法。 了解“文件包含”与预处理的应用。 了解条件编译的几种形式。 掌握各种位运算符,运算规则和优先级。 了解位运算的实际应用。 了解位段的定义和应用。 本章目标 了解一些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 无参数宏定义,如 if(x=YES) printf(“correct!n”); else if (x=NO) printf(“error!n”); 展开后: if(x=1) printf(“correct!n”); else if (x=0) printf(“error!n”);,不带参数宏定义 一般形式: #define 宏名 宏体 功能:用指定标识符(宏名)代替字符序列(宏体),如 #define YES 1 #define NO 0 #define PI 3.1415926 #define OUT printf(“Hello,World”);,宏体可缺省,表示宏名 定义过或取消宏体,例 #define MAX MAX+10 (),例 #define PI 3.14159 printf(“2*PI=%fn”,PI*2); 宏展开:printf(“2*PI=%fn”,3.14159*2);,例 #define WIDTH 80 #define LENGTH WIDTH+40 var=LENGTH*2; 宏展开:var= 80+40 *2;,1.2.2 不带参数宏定义,宏定义的规则 宏名一般习惯用大写字母表示,以便与变量名相区别 宏定义不是C语句,不必在行末加分号 在进行宏定义时,可以引用已定义的宏名,可以层层替换。 只作字符替换,不分配内存空间。,#define R 3.0 #define PI 3.1415926 #define L 2*PI*R #define S PI*R*R main() printf(“L=%fnS=%fn”,L,S); ,结果: L = 18.849556 S = 28.274333,1.2.2 不带参数宏定义,宏定义的特点 宏名一般习惯用大写字母表示 提高程序的通用性 宏名的有效范围为定义命令之后到本源文件结束 可以用#undef命令终止宏定义的作用域 宏定义只作简单的替换,不作正确性检查,1.2.3 带参数宏定义,一般形式: #define 宏名(参数表) 宏体,例 #define S (r) PI*r*r 相当于定义了不带参宏S,代表字符串“(r) PI*r*r”,宏展开:形参用实参换,其它字符保留 宏体及各形参之间应加空格 注意宏体的括号,例 #define S(a,b) a*b area=S(3,2); 宏展开: area=3*2;,不能加空格,例 #define POWER(x) x*x x=4; y=6; z=POWER(x+y); 宏展开:z=x+y*x+y; 一般写成: #define POWER(x) (x)*(x) 宏展开: z=(x+y)*(x+y);,1.2.2 带参数宏定义,带参数宏定义的特点 带参宏定义中,宏名和形参表之间不能有空格出现 例如: #define MAX(a,b) (ab)?a:b 写为: #define MAX (a,b) (ab)?a:b 将被认为是无参宏定义,宏名MAX代表字符串 (a,b)(ab)?a:b 在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义 在宏定义中的形参是标识符,而宏调用中的实参可以是表达式 在宏定义中,字符串内的形参通常要用括号括起来以避免出错,#define SQ(y) (y)*(y) main() int a,sq; printf(“input a number: “); scanf(“%d“, ,1.2.2 带参数宏定义,带参的宏和带参函数很相似,但有本质上的不同,1.2.2 带参数宏定义,带参的宏和带参函数很相似,但有本质上的不同,宏定义例,函数例,main() int i=1; while(i=5) printf(“%dn“,SQ(i+); SQ(int y) return(y)*(y); ,#define SQ(y) (y)*(y) main() int i=1; while(i=5) printf(“%dn“,SQ(i+); ,1.3 文件包含,函数例,功能:一个源文件可将另一个源文件的内容全部包含进来 一般形式: #include “文件名” 或 #include ,处理过程:预编译时,用被包含文件的内容取代该预处理命令,再对“包含”后的文件作一个源文件编译, 直接按标准目录搜索 “” 先在当前目录搜索,再搜索标准目录,1.3 文件包含,被包含文件内容 源文件(*.c) 头文件(*.h),宏定义 数据结构定义 函数说明等,文件包含可嵌套,1.3 文件包含,例子,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 #define MAX 100 Int main(void) #if MAX99 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 #define T 10 int main(void) #ifdef t Printf(“Hi Tn”); #else Printf(“Hi anyonen”); #endif #ifndef M Printf(“M Not Definedn”); #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“, #endif ,阶段小节,宏定义的特点和宏定义的取消 带参数宏定义要注意的几个细节 条件编译主要应用在那几个方面,它有几种使用方法 Include 包含文件的两种方法和他们之间的区别特点,1.5 位运算,按位与运算 按位或运算 按位异或运算 求反运算 左移运算 右移运算,1.5 位运算,位运算符的含义 位运算是指进行二进制位的运算。 功能: c语言提供对内存单元的二进制位的操作,使得c语言能够编写系统软件. 位运算符 &: 按位与 |: 按位或 : 按位异或 : 取反 : 右移,1.5 位运算,要点: 位运算除以外,均为二目运算; 运算对象只能为整型或字符型数据. 各个位运算符号的使用:,1.5.1按位与运算,按位与& 格式:x&y 主要用途:取(或保留)1个数的某(些)位,其余各位置0 规则:对应位均为1时才为1,否则为0:3&9=1。 例如,3&9=1: 0011 & 1001 0001=1,1.5.2 按位或运算,按位或| 格式:x|y 主要用途:参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1 规则: :对应位均为0时才为0 ,否则为1:3|9=11 。 例如,3|9=11: 0011 | 1001 1011=11,1.5.3 按位异或运算,按位异或 格式: xy 规则:对应位相同时为0,不同时为1:39=10 。 主要用途:使1个数的某(些)位翻转(即原来为1的位变为0,为0的变为1),其余各位不变 例子: 00001001 00000101 00001100 (十进制为12),1.5.4求反运算,求反 格式: y 规则:各位翻转,即原来为1的位变成0,原来为0的位变成1:在IBM-PC机中,00xffff,9=0xfff6。 主要用途:间接地构造一个数,以增强程序的可移植性,1.5.5 左移运算,按位左移 格式:x 位数 规则:使操作数的各位左移,低位补0,高位溢出:52=20。,1.5.6 右移运算,按位左移 格式:x位数 规则:使操作数的各位右移,移出的低位舍弃;高位: 对无符号数和有符号中的正数,补0; 有符号数中的负数,取决于所使用的系统:补0的称为“逻辑右移”,补1的称为“算术右移”。例如,20 2=5 说明 x、y和“位数”等操作数,都只能是整型或字符型数据。除按位取反为单目运算符外,其余均为双目运算符。 参与运算时,操作数x和y,都必须首先转换成二进制形式,然后再执行相应的按位运算。 例如,5 2=5:10100 00101。,1.5.6 位运算例子,例2 题目:从键盘上输入1个正整数给int变量num,输出由811位构成的数(从低位、0号开始编号) 基本思路: (1)使变量num右移8位,将811位移到低4位上。 (2)构造1个低4位为1、其余各位为0的整数。 (3)与num进行按位与运算。 /*程序功能:输出一个整数中由811位构成的数*/,main() int num, mask; printf(“Input a integer number: “); scanf(“%d“, ,程序运行情况: Input a integer number:1000 result=0x3 程序说明: ( 0 4) 按位取0的反,为全1;左移4位后,其低4位为0,其余各位为1; 再按位取反,则其低4位为1,其余各位为0。这个整数正是我们所需要的。,1.5.6 位运算例子,例1 题目:从键盘上输入1个正整数给int变量num,按二进制位输出该数。,#include “stdio.h“ main() unsigned int num, mask, i; printf(“Input a integer number: “); scanf(“%d“, ,程序运行情况: Input a integer number:1000 1000=0000,0011,1110,1000B,1.6 位段,位域的定义和位域变量的说明 位域的使用,1.6.1位域的定义和位域变量的说明,位段的含义 位段是以位为单位定义长度的结构体类型中的成员. 位段的构成 例如:struct pack unsigned a:2; unsigned b:6; unsigned c:8; int x; data; 这个结构体类型的变量在内存中的情况为:,1.6.1位域的定义和位域变量的说明,也可以使各个字段不恰好占满一个字节 struct pack unsigned a:2; unsigned b:6; unsigned c:4; int x; data; 则内存中的分配形式为: 说明: 此处:a,b,c共占2个字节中的12位,空闲4位, int型的x从一个新的字节开始.,1.6.1位域的定义和位域变量的说明,位域的使用要点 一个位域必须存储在同一个字节中,不能跨两个字节 在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。,struct bs unsigned a:4 unsigned :0 /*空域*/ unsigned b:4 /*从下一单元开始存放*/ unsigned c:4 ,1.6.1位域的定义和位域变量的说明,位域的使用要点 位域可以无位域名,这时它只用来作填充或调整位置。,struct k int a:1 int :2 /*该2位不能使用*/ int b:3 int c:2 ;,1.6.2 位域的使用,若某个位段要从新的存储单元开始,可以这样定义: 注意:长度为0的位段的作用是使下一个位段的内容从新的存储单元开始存放。 要点:注意每个字段的最大取值范围.如:data.a的取值只能是:03, 因为两位二进制最大表示的数为3. 方法:通过结构体成员来应用: 如: data.a=2; data.b=6;,struct pack unsigned a:2; unsigned :0; unsigned b:4; unsigned c:4; int x; data;,1.6.2 位域的使用,位域的使用要点 位段可以用十进制的整型形式输出,也可以用其他的整型格式输出(如八进制,十六进制和无符号),位段以整型的形式参加算术运算. 分析下面的程序:,main() struct pack unsigned a:2; unsigned b:3; unsigned c:1; unsigned d:4; unsigned e:3; ; unionstruct pack qp; unsigned i;abc; abc.i=255; printf(“%dn”,abc.qp.d); ,1.6.2 位域的使用,位域的使用例子,main() struct bs unsigned a:1; unsigned b:3; unsigned c:4; bit,*pbit; bit.a=1; bit.b=7; bit.c=15; printf(“%d,%d,%dn“,bit.a,bit.b,bit.c); pbit= ,1.7 其他预处理关键字,#error 使用defined #line #pragma #和# 预定义宏,1.7.1 #error,#error指令强制编译程序停止编译, 主要用于程序调试 #error指令的一般形式是 #error error-message 注意: 宏串error-message不用双引号包围 可以自定义错误内容,1.7.2 使用defined,确定是否定义宏名字的方法 defined操作符的一般形式如 defined macro-name define与ifdef: #if defined MY 或 #ifdef MY 感叹号”!”来反转相应的条件 #if !defined DEBUG Printf(“Final Version!n”); #endif,1.7.3 #line,#line指令改变_LINE_和_FILE_的内容 #line的一般形式 #line number “filename” 主要用于调试和特殊应用,1.7.5 #和#,操作符#通常称为字符串化的操作符 预处理程序把以下的语句: Printf(mkstr(I like C); 变成 Printf(“I like C”);,#include #define mkstr(s) #s int main(void) Printf(mkstr(I like C); Return 0; ,1.7.5 #和#,“#”可以把两个独立的字符串连接成一个字符串,#include #define SORT(X) sort_function # # X void main(void) char *array; int elements,element_size; SORT(3) (array,elements,element_size); ,结果: SORT(3) 转化为sort_function3 SORT(3) (array,elements,element_size)转化为 sort_function3(array,elements,element_size,1.7.6 预定义宏,_DATE_ 进行预处理的日期(“Mmm dd yyyy”形式的字符串文字) _FILE_ 代表当前源代码文件名的字符串文字 _LINE_ 代表当前源代码中的行号的整数常量 _TIME_ 源文件编译时间,格式微“hh:mm:ss” _func_ 当前所在函数名,1.7.6 预定义宏,例子,#include #include voi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 校园卫生安全知识培训课件
- 食品操作考试题及答案
- 经济法学试题及答案
- 辽宁省烟草面试题及答案
- 校内活动安全知识培训课件
- 医学基础知识常考题(含答案)
- 2025年雇佣执行经理合同范本
- 医疗器械法规知识培训试题及答案(单体药店或连锁门店)
- 2025年VTE、伤口造口相关知识培训后考核试题及答案
- 树木寻访记探究课件
- 临沧市市级单位遴选(选调)考试试卷真题及答案2022
- 三级教育卡、培训记录和花名册
- 拜复乐-产品基础知识
- 生物制品生产工艺过程变更管理技术指导原则
- 建筑施工现场签证单(模板)
- GBZ(卫生) 49-2014职业性噪声聋的诊断
- GB/T 9729-2007化学试剂氯化物测定通用方法
- GB/T 7588.2-2020电梯制造与安装安全规范第2部分:电梯部件的设计原则、计算和检验
- GB/T 13560-2017烧结钕铁硼永磁材料
- 三视图及尺寸标注课件
- 混凝土配合比验证检验委托书模板
评论
0/150
提交评论