




已阅读5页,还剩28页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
精品文档 1欢迎下载 1 1 的作用的作用 是将其后的变量直接转换为字符串 void WriteLog arg printf s d arg arg 2 2 的作用的作用 的作用是连接两个变量 如 define combine converse str x y x y int Err int Num printf s combine converse str Err Num 结果为 ErrNum 再如 int a 1 int b 2 int ab 3 精品文档 2欢迎下载 printf d a b 结果为 3 后面那句相当于 printf d ab 3 3 do do while 0 while 0 作用作用 1 空的宏定义避免 warning define foo do while 0 2 存在一个独立的 block 可以用来进行变量定义 进行比较复杂的实现 3 用在宏定义上并且当宏定义需要定义成多条语句的组合时 可以保证这几条语句是一个 整体的 并且可以消除使用这个宏定义后添加 所带来的报错 例如 define aaa x y do int a 0 int b 0 函数 1 x 函数 2 y while 0 调用 aaa x y 时不会报错并且如果使用 if m aaa 1 2 else aaa 3 4 时运行也不会使某些语句没有被运行到 精品文档 3欢迎下载 4 4 数组名的使用数组名的使用 A 数组名作为函数参数数组名作为函数参数 数组名用在某个函数 A 的参数中时 处于函数传递效率原因 会被强制转换成了指针 此后在函数 A 内就完全是一个值等于对应数组首地址的指针 变量 可自加自减等 注意 只有在作为函数参数的情况下才会将数组名强制转换成指针 其他的都不会转 换 另 数组名作为函数参数传递时 函数声明的写法有多种 int aaa char x int aaa char x 1 int aaa char x 100 int aaa char x 作为函数参数时的参数声明也和普通的数组定义一样要合法 比如不能 int aaa char x 0 因为定义一个数组也不能用 char x 0 来定义 编译器在检查参数的声明合法 后 如果发现参数是数组 就会强制转换成指针 所以 int aaa char x 1 和 int aaa char x 100 的结果是一样的 B 数组名用在数组名用在 sizeofsizeof 上上 结果返回的是整个数组所占空间的大小 而不是一个指针的长 度 C 数组名与数组名与 printf a x n a printf printf printf printf printf printf int 精品文档 4欢迎下载 printf 结果 a 12ff34 实际内存中保存的就是 精品文档 5欢迎下载 即首地址 0 x12ff0c 0 x00423018 0 x0042f2f4 0042201c 其中 0 x00423018 地址所保存 的就是 Bill 所以数组名 Name 0 x12ff0c printf printf printf printf Name x n Name printf Name x n Name printf Name 0 x n Name 0 printf Name 0 x n Name 0 printf printf printf int printf 结果是 Name p Name 不能直接用不能直接用 intint p Name p Name 5 5 常量的定义和指针常量的定义及使用常量的定义和指针常量的定义及使用 1 常量的定义 const int a 10 在其他地方不允许修改 a 的值 否则会编译不通过 精品文档 6欢迎下载 也可以写成 int const a 10 一样的 2 指针常量的定义和使用 有 3 种定义 const int pi 和 int const pi 以及 int const pi 1 前两种情况一样的 没有区别 1 如果 const 修饰在 pi 前 前 2 种情况 则不能改的是 pi 即不能 类似这样 pi 50 赋值 而不是指 pi 2 如果 const 是直接写在 pi 前 后一种情况 则 pi 不能改 即不能类似 这样 pi tmp x x y y tmp printf x d y d n x y main int a 4 b 6 Exchg1 a b 精品文档 7欢迎下载 printf a d b d n a b return 0 2 地址传递 void Exchg2 int px int py int tmp px px py py tmp printf px d py d n px py main int a 4 int b 6 Exchg2 printf a d b d n a b return 0 3 引用传递 void Exchg3 int 精品文档 8欢迎下载 x y y tmp printf x d y d n x y main int a 4 int b 6 Exchg3 a b printf a d b d n a b return 0 4 变长参数传递 使用省略号 指定参数表 使用的宏及其定义 x86 中 define va start crt va start define va arg crt va arg define va end crt va end typedef char va list define ADDRESSOF v int argno 0 char para va start argp fmt while 1 para va arg argp char if strcmp para 0 break printf Parameter d is s n argno para argno va end argp return 0 精品文档 10欢迎下载 int main demo DEMO1 This is a demo return 0 运行结果 详解 1 函数的参数和局部变量都是存储在栈里 2 栈的内存分配是按从高地址到低地址分配的 而其他的正常是从小到大分配 比如全局 变量定义等 即先分配高地址的 再分配低地址的内存 3 所有的函数参数 不管是定长参数还是变长参数 入栈都是从右到左入栈 如调函数 a x y z 则 z 先入栈 并存在栈底 高地址 其次 y 其次 x 4 数据在内存里的存储默认都按照字节对齐来存储 x86 按照 4 字节对齐 如 int aaa char a char b char c return int a b c 调用函数 aaa 5 6 7 时 内存中是这样的 所以 如果是数值 则会直接存储在栈中 如果是指针类型 如字符串 则会把指针值 即字符串首地址的值 存储在栈中 从右到左依次按照从高地址到低地址存储 精品文档 11欢迎下载 如实例的程序调用 demo DEMO1 This is a demo 得到的堆栈为 即 0 x0012FEFb 开始往低地址方向的部分为此函数的栈空间 存入的值分别为 0 x00422038 0 x00422058 0 x0042204C 0 x00422034 0 x00422044 0 x0042203C 这 6 个地 址分别所指向的实际上就是静态存储区存储 demo a is This DEMO1 的地 方 见图 另 如果改成 demo DEMO1 1 2 a demo 则其中的数字 1 2 直接保存在栈 中 见图 精品文档 12欢迎下载 5 define INTSIZEOF n sizeof n sizeof int 1 return 0 这个函数编译出来为 test3 exe 然后在 dos 命令行中调用 得到 D test3 exe aaa bbb ccc argc 4argv test3 exe argv aaa argv bbb argv ccc 精品文档 23欢迎下载 其中 test3 exe 文件名本身也算一个参数 所以 dos 命令行调用 test3 exe 时 操作系 统传递给 test3 exe 的实参实际上就是参数个数是 4 参数为 test3 exe aaa bbb ccc 17 17 哪些语句句尾要用分号 哪些语句句尾要用分号 C 语言规定 所有的语句必须要以分号 结尾 而预编译命令不属于语句 末尾不加分号 如 include if else elif endif define 等 18 18 volatilevolatile 关键字的作用关键字的作用 volatile 修饰的量是不稳定的 可能会经常被改变或者被其他线程使用并改变其值 所以 用 volatile 关键字就限制了执行器在执行的时候每次访问其值必须去内存中去取 而不能 被编译器优化在内部寄存器中 19 19 typedeftypedef 的用法的用法 1 用于对普通数据类型定义别名 例如 typedef unsigned int UINT 2 用于定义指针 例如 typedef int PINT 注意 虽然 与 PINT 之间没有空格 但是实际上跟 typedef int PINT 是一样的 是跟前面的结合的 3 用于对结构体 枚举 联合体类型定义别名 例如 typedef union int uid unsigned char mid ID U 精品文档 24欢迎下载 4 用来定义数组 例如 typedef int aNum 2 aNum x 5 用来定义函数相关 一般都是定义函数指针 例如 typedef int pf int char 6 用来简化复杂的定义 其实就是前面几个的综合 注意 定义普通类型和指针以及结构体注意 定义普通类型和指针以及结构体 联合体联合体 枚举 都是枚举 都是 typedef typedef 原定义原定义 别名别名 的方式 而定义数组和函数指针是按照的方式 而定义数组和函数指针是按照 替换原定义的变量替换原定义的变量 的定义方式来定义 的定义方式来定义 是不同的 是不同的 typedef 使用范例 include stdafx h include stdio h typedef unsigned int UINT typedef struct UINT uid char mid STU T typedef STU T STU T REF typedef int aArray 2 typedef void fFunc int void print1 int x printf d x int main int argc char argv 精品文档 25欢迎下载 UINT i 3 STU T st1 STU T REF tStu aArray b fFunc fTestPrint tStu tStu uid i b 0 1 b 1 2 fTestPrint fTestPrint tStu uid return 0 20 20 typedeftypedef 和和 definedefine 区别区别 1 作用上 typedef 是定义一个类型 使用时与普通的变量类型用法完全相同 define 是宏替换 2 语法上 typedef typedef char INT8 define define INT8 char typedef 在执行时执行 define 在预编译时执行 typedef 是一条语句 后要分号 define 是预编译指令 后无需 分号 typedef 别名 替换者在后 原名在前 define 别名 替换者在前 原 名在后 精品文档 26欢迎下载 这点可以这样记忆 执行前 使用前 执行后 使用后执行前 使用前 执行后 使用后 define 是预编译 typedef 是语句 所以 define 的执行是前 我们使用的那个也在前 即 define INT8 char INT8 在前 原名在后 typedef 的执行是后 我们使用的那个也在后 即 typedef char INT8 我们使用的 INT8 也在后 typedef 只能用于类型定义 define 不受限制 除了类型外还可以是数 值等 typedef 不能带参数 define 可以带参数 3 作用范围上 语句 typedef int PINT PINT a b 与 define PINT int PINT a b 中的 PINT a b 是不一样的 前者相当于 int a int b 而后者相当于 int a b 即 int a int b 21 21 复杂定义的剖解方法和用复杂定义的剖解方法和用 typedeftypedef 简简 化化 可以用 右左法则 来分析 所谓右左法则 就是先找到没有定义的变量 这个就是分析 的起点 也是变量的最终属性 从这个起点 根据优先级顺序开始分析 如优先级相同 则按照先右再左分析 遇到 就根据 是最高优先级来分析 跳出 后同样按先右后左分 析 以此类推 例如 int int a 5 int a 5 int char char 找到 a 是未定义变量 所以这就是起点 优先级比 高 所以 a 与 5 先结合 a 5 是一个具有 5 个元素的数组 再与 结合 得到每个元素都是指 针 跳出 再向右结合 得到前面的指针 数组里的每个都是指针的元素 指向一个函数 函数的参数是 int char 返回值是 int voidvoid b 10 b 10 void void b 是一个有 10 个元素的数组 每个元素都是指针 这些 指针中每一个指针指向一个函数 函数的参数是 void 实际上它又是个函数指针 指针所指向的函数的参数为空 返回值为 void 返回值是 void double pa 9 double pa 9 pa 是一个指针 这个指针指向具有 9 个元素的数组 9 个元 精品文档 27欢迎下载 素中每一个都是 double 即指针 指针指向一个函数 函数的参数为空 返回值为 double 使用使用 typedeftypedef 简化 简化 用用 typedeftypedef 来对复杂定义做简化很简单 从小到大 抠出合适的定义单位来对复杂定义做简化很简单 从小到大 抠出合适的定义单位 从阅读理解和使从阅读理解和使 用上合适用上合适 然后用别名代替 最后在前面加个 然后用别名代替 最后在前面加个 typedeftypedef 关键字即可 关键字即可 例如 例如 1 int a 5 int char 首先从小到大 抠出合适的定义单位 a 5 是个数组 方便理解 别名用 ARRAY 替代 则成了 int ARRAY int char 前加一个 typedef 即 可 typedef int ARRAY int char 2 void b 10 void typedef void pfA void pfA b 10 进一步化简 typedef void pfB typedef void pfA pfB pfA b 10 3 double pa 9 typedef double PF PF pa 9 22 22 structstruct enumenum 和和 unionunion 的定义以及用的定义以及用 typedeftypedef 来定义来定义 定义 struct enum union 类型名 成员类型 成员名 成员类型 成员名 其中如果直接在 后定义变量的话 可以省略类型名不写 声明 struct enum union 类型名 变量名 例如 精品文档 28欢迎下载 定义 struct student s char name int age int class int number 声明 struct student s stu a 用用 typedeftypedef 来定义来定义 typedef struct enum union 类型名 成员类型 成员名 别名 其中可以省略类型名 声明 别名 变量名 例如 定义 typedef struct student td char name int age int class int number STUDENT T 使用 STUDENT T stu a 用用 typedeftypedef 来定义结构体来定义结构体 枚举枚举 联合体实际上就是 联合体实际上就是 typedeftypedef 原定义原定义 别名别名 与定义普通与定义普通 的类型是一样的 如的类型是一样的 如 typedeftypedef charchar INT8 INT8 23 23 typedeftypedef 的的 2 2 个使用陷阱个使用陷阱 1 1 用在用在 constconst 或或 volatilevolatile 修饰的语句时的陷阱修饰的语句时的陷阱 typedef 用在 const 修饰的语句和用在 volatile 修饰的语句的注意点是一样的 下面以 const 为例说明 typedef int PINT const PINT p1 上面 2 条语句 先用 typedef 声明了之后 再用 const 修饰 实际结果不是 const int p1 而是 int const p1 根我们想象的不一样的 不能直接类似 define 那样替换的 因为 typedef 定义的 PINT 是地址 所以 const 修饰的是地址 也就是 p1 不能被修改 而 不是整个 int p1 二维的也类似 typedef int PPINT int i 2 int p PPINT p1 是 p1 不能被修改 而不是 p1 2 2 typedeftypedef 不能跟存储类关键字同时使用不能跟存储类关键字同时使用 typedef 在语法上属于存储类关键字 如 auto static extern mutable register 精品文档 29欢迎下载 等 不能再跟另外的存储类关键字同时使用了 虽然它并不实际影响存储特性 如 不能 typedef static int SINT 编译会提示 more than one storage class specified 使用了一个以上的存储类关键字 24 24 为什么要使用为什么要使用 externextern C C extern C 是用来修饰 extern 声明的 使 extern 按照 C 的形式去声明 而不是 C 的形 式 是为了兼容 C 与 C 混合编程时防止 c 程序调用 c 程序时找不到对应函数而设置的 详细解释 c 为了实现面相对象而引入函数重载 重载就是允许同样的函数名而参数不同 因为面相对象就要求能进行函数重载 因为面相对象是把一个行为 即方法 函数 对应的各 种情况 即不同类型的参数 比如说 println 函数是打印 但是有时可能传递的参数只是字 符串 有时候既有数字 又有字符串 不止一个 可能各种使用情况参数类型和个数都不 同 都封装在对象内部 而不直接对外呈现 通过改变函数的编译方法来实现 实际上就 是编译时用函数构建符号表的时候生成的对应的函数名不同 比如同样的函数 foo int int c 语言编译在符号表中是 foo 而 c 编译在符号表中却是 foo int int 正是由于这点 所以 cpp 代码在调用函数时总是寻找按照 c 编译的符号表的形式来寻找 函数名 而 c 文件编译出来的放在符号表的函数名却不是 c 所想象那样的 所以 cpp 文 件在调用 c 文件函数时就找不到函数了 所以需要使用 extern C 来修饰 extern 意思是 告诉 C 编译器 这句 extern 要按照 c 的方式去寻找函数 具体的结合实例的解析和 extern C 的使用方法如下 以以下例子说明 test6 cpp extern int add int x int y int main int argc char argv add 2 3 return 0 精品文档 30欢迎下载 cExample c int add int x int y return x y 过程分析 1 在编译 test6 cpp 文件的时候 因为是 cpp 文件 在编译的时候就会按照 c 的方式去 编译 也就是在寻找 add 函数的时候根据 extern int add int x int y 语句实际上 是寻找 add int int 符号表的 因为有这个 extern 语句 所以编译可以通过 2 在编译 cExample c 的时候 因为是 c 文件 所以按照 c 的方式去编译 得到 add 函数 对应在符号表上函数名是 add 当然因为没有语法错误编译也能通过 3 链接的时候 链接到 cpp 生成的编译文件 linux 下是 o 的调用 add 函数语句时 会 去其他文件的符号表去找 add int int 函数 实际上编程者的本意是函数在 cExample c 中定义的 add 函数 但是在 cExample c 对应的编译文件 linux 下是 cExample o 的符号表中没有找到 add int int 符号 因为 add 函数被用 c 的方式编 译成了 add 了 在其他文件中也没有找到 所以就会报这个符号无法解析的错误 解决方法 在 cpp 文件中的 extern 函数的时候使用 extern C 可以有 2 种书写方式 1 用 extern C 代替 extern 语句 改成 extern C int add int x int y 即可 2 用 extern C 将所有的 extern 语句括起来 extern C extern int add int x int y 这样做的好处就是可以一次性的把所有的 extern 语句都用 extern C 限制了 中间还 可以有其他的语句 例如 define typedef 等 对它们没有影响 注意 使用这种方法要注意 extern C 只有 c 编译器能识别出来 而 c 编译器不能识别 所以一定不能把 extern C 放在 c 编译器所编译到的地方 因为 c 文件是 c 编译器编译的 所以不要把
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 高考试题模拟卷及答案
- 2025企业单位临时工劳动合同模板【正式】
- 甘孜养护工考试题及答案
- 福清物理中考试题及答案
- 动火作业关考试题及答案
- 2025年历年中考英语常考250例语法汇编 (珍藏版)
- 中国聚乙烯醇水凝胶项目创业投资方案
- 电工理论考试题目及答案
- 电厂管理考试题目及答案
- 德格消防考试题及答案解析
- 车间落地品管理办法
- 培训机构续费沟通
- 《往事依依》课堂实录
- 软笔书法课件横的写法
- 精益物流课件
- SYH公司爬坡生产:产能学习曲线构建与应用探索
- 《液冷数据中心设计标准》(征求意见稿)
- 水质采样监测培训课件
- 2025年全国国家版图知识竞赛(中小学组)题库及答案
- 不动产登记员考试试题附答案
- 房屋设备设施保养方案(3篇)
评论
0/150
提交评论