详解C语言之预处理(下)

目录
  • #define定义宏带副作用的宏参数
    • #define定义宏的优点
    • #define定义宏劣势
  • 预处理
    • 预定义符号
    • 预处理指令
    • 条件编译
      • 1.调试性代码
      • 2.防止重复的头文件多次编译
  • 总结

#define定义宏带副作用的宏参数

我们来看如下一段代码

结果分别为12,11,13

当参数替换后,首先判断表达式 (a++)>(b++)?,判断后a的值加1 b的值加1,然后执行表达式(b++)此时执行的值为12,执行完成后b的值加1,则a的值为11,b的值为13。可以看出对于这种情况下的宏是带有副作用的,可能会导致不可预料的结果

#define定义宏的优点

实现以下代码,用函数好还是宏好?

1.用于调用函数和返回代码的时间可能比这个小型计算所需的时间更多,所以宏在速度上和规模上更胜一筹

2.函数的参数必须声明为特定的类型,所以函数只能在类型合适的表达式使用,而宏则与类型无关,所以如果比较浮点型时使用函数就会有警告

#define定义宏劣势

1.每次使用宏时,一段宏定义的代码会插入到代码中,除非宏比较短,否则将大幅增加代码的长度

2.由于存在信息差,宏是没办法调试的。我们看到的是宏定义的名字,而实际运行是宏定义的代码。例:

看似代码没错,但实际上是因为无法调试宏而找不出错误。

3.宏由于与类型无关,也就不够严谨

4.宏可能带来运算符优先级的问题,容易导致结果出错

预处理

预定义符号

__FILE__          进行编译的源文件

__DATE__        文件被编译的日期

__TIME__         文件被编译的时间

__LINE__          文件当前的行号

__STDC__         若编译器遵循ANSI C标准 则值为1,否则未定义

预处理指令

#define  宏定义

#undef  撤销已定义宏名

#include  使编译程序将另一源文件嵌入到带有#include的源文件中

#ifdef    如果定义

#ifndef    如果未定义

#endif

预处理指令为上述以及其他#开头的指令

条件编译

能够让语句选择编译或者放弃

常用于调试性的代码,删除可惜,保留又碍事,或者防止重复头文件多次编译

1.调试性代码

若未定义,则不会编译其中的代码

2.防止重复的头文件多次编译

还可以用#pragma once

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 详解C语言#define预处理宏定义

    目录 #define介绍: #define宏定义无参的一般形式为:#define  标识符 常量 #define宏定义有参的一般形式为:#define  标识符(参数表) 表达式 #运算符: ##运算符: 可变宏...和__VA_ARGS__: 开发项目中常用的宏定义: #define介绍: C语言里可以用#define定义一个标识符来表示一个常量.特点是:定义的标识符不占内存,只是一个临时的符号,预编译后这个符号就不存在了,也不做类型定义.预编译又叫预处理.预编译就是编译前的处理.这个操作是在

  • C语言预处理详解

    目录 一,预定义符号 二,#define 1,#define 定义标识符 2,#define 定义宏 3,#define 替换规则 三,##的作用 1,概念 2,带副作用的宏参数 3,宏和函数对比 四,命名约定 1,#undef 2,文件包含 总结 一,预定义符号 __FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DATE__ //文件被编译的日期 __TIME__ //文件被编译的时间 __STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义 in

  • 详解C语言编程中预处理器的用法

    预处理最大的标志便是大写,虽然这不是标准,但请你在使用的时候大写,为了自己,也为了后人. 预处理器在一般看来,用得最多的还是宏,这里总结一下预处理器的用法. #include <stdio.h> #define MACRO_OF_MINE #ifdef MACRO_OF_MINE #else #endif 上述五个预处理是最常看见的,第一个代表着包含一个头文件,可以理解为没有它很多功能都无法使用,例如C语言并没有把输入输入纳入标准当中,而是使用库函数来提供,所以只有包含了stdio.h这个头文

  • C语言预处理预编译命令及宏定义详解

    目录 程序翻译环境和执行环境 翻译环境:详解编译+链接 1. 编译 - 预处理/预编译 test.c ---- test.i 2. 编译 - 编译 test.i ---- test.s 3. 编译 - 汇编 test.s ---- test.obj 4. 链接 test.obj ---- test.exe 运行环境 预处理/预编译详解 #define 定义标识符 #和## #的作用 ##的作用 命名约定 命令行定义 条件编译 常见的条件编译指令 文件包含 offsetof(宏类型,成员名字)偏移

  • C语言程序的编译与预处理详解

    目录 一.程序的编译 1. 编译阶段 2.链接 二.预处理详解 1.预定义符号 2.#define定义的标识符 3.#define定义的宏 4.#unef 总结 一.程序的编译 我们写的源文件(*.c)是经过怎样的处理生产可执行文件(*.exe)的呢?这种处理有两个步骤-编译和链接.源文件在编译阶段通过编译器将每个源文件转换为目标文件(这些文件是可执行的机器指令),再通过链接器将其捆绑到一起,生成一个完整的可执行程序. 1. 编译阶段 编译阶段可细分为3个阶段:预处理(即预编译).编译.汇编 预

  • 详解C语言之预处理

    目录 程序的翻译环境 编译 预编译: 编译: 汇编: 链接 合并段表: #define的用法 1.#define定义标识符,例如 2.#define定义宏 3.#define实现将参数插入到字符串中 总结 程序的翻译环境 源文件被转换成可执行的机器指令时所处的环境称为翻译环境. 由源文件(.c)转换成可执行文件(.exe)需要两步 编译通过编译器实现,链接通过链接器实现 每个源文件都会经过编译器处理后生成对应的目标文件,然后链接器将目标文件和链接库链接在一起生成可执行程序 编译和链接的具体操作

  • 详解C语言之预处理(下)

    目录 #define定义宏带副作用的宏参数 #define定义宏的优点 #define定义宏劣势 预处理 预定义符号 预处理指令 条件编译 1.调试性代码 2.防止重复的头文件多次编译 总结 #define定义宏带副作用的宏参数 我们来看如下一段代码 结果分别为12,11,13 当参数替换后,首先判断表达式 (a++)>(b++)?,判断后a的值加1 b的值加1,然后执行表达式(b++)此时执行的值为12,执行完成后b的值加1,则a的值为11,b的值为13.可以看出对于这种情况下的宏是带有副作用

  • 详解C语言的预处理效果

    目录 前言 一.预定义符号 二.#define 1.宏 2.宏与函数 3.带副作用的宏参数 4. 宏和函数的不同 5.#undef 三.条件编译 四.文件包含 1.函数库文件包含 2.本地文件包含 总结 前言 编译一个C语言程序涉及很多步骤.其中第一个步骤被称为预处理.C语言的预处理器在源代码编译之前对其进行一些文本性质的操作.它的主要任务包括删除注释.插入被#include指令包含的文件内容.定义和替换由#define指令定义的符号,同时确定代码的部分内容是否应该根据一些条件编译指令进行编译.

  • 详解C语言之预处理(上)

    目录 程序的翻译环境 编译 预编译: 编译: 汇编: 链接 合并段表: #define的用法 1.#define定义标识符,例如 2.#define定义宏 3.#define实现将参数插入到字符串中 总结 程序的翻译环境 源文件被转换成可执行的机器指令时所处的环境称为翻译环境. 由源文件(.c)转换成可执行文件(.exe)需要两步 编译通过编译器实现,链接通过链接器实现 每个源文件都会经过编译器处理后生成对应的目标文件,然后链接器将目标文件和链接库链接在一起生成可执行程序 编译和链接的具体操作

  • 详解C 语言项目中.h文件和.c文件的关系

    详解C 语言项目中.h文件和.c文件的关系 在编译器只认识.c(.cpp))文件,而不知道.h是何物的年代,那时的人们写了很多的.c(.cpp)文件,渐渐地,人们发现在很多.c(.cpp)文件中的声明语句就是相同的,但他们却不得不一个字一个字地重复地将这些内容敲入每个.c(.cpp)文件.但更为恐怖的是,当其中一个声明有变更时,就需要检查所有的.c(.cpp)文件. 于是人们将重复的部分提取出来,放在一个新文件里,然后在需要的.c(.cpp)文件中敲入#include XXXX这样的语句.这样即

  • 详解C语言结构体,枚举,联合体的使用

    目录 一.匿名结构体 二.结构体的自引用 1.声明时不要自己引用自己 2.结构体重命名时不能使用重命名 三.结构体内存对齐规则 1.结构体内存计算 2.结构体嵌套 3.通过调整结构体成员顺序,压缩内存 四.存在内存对齐的原因 五.修改默认对齐数 六.结构体传参 七.位段 1.位段在内存中的存储 2.位段的跨平台问题 八.枚举 1.枚举的定义 2.枚举的优点 九.联合体(共用体) 1.联合体大小的计算 2.使用联合体判断计算机的大小端字节序 一.匿名结构体 struct { char name[2

  • 详解C语言 三大循环 四大跳转 和判断语句

    三大循环for while 和 do{ }while; 四大跳转 : 无条件跳转语句 go to; 跳出循环语句 break; 继续跳出循环语句 continue; 返回值语句 return 判断语句 if,if else,if else if else if...else ifelse 组合 if(0 == x) if(0 == y) error(): else{ //program code } else到底与那个if配对 C语言有这样的规定: else 始终与同一括号内最近的未匹配的if语

  • 详解C语言gets()函数与它的替代者fgets()函数

    在c语言中读取字符串有多种方法,比如scanf() 配合%s使用,但是这种方法只能获取一个单词,即遇到空格等空字符就会返回.如果要读取一行字符串,比如: I love BIT 这种情况,scanf()就无能为力了.这时我们最先想到的是用gets()读取. gets()函数从标准输入(键盘)读入一行数据,所谓读取一行,就是遇到换行符就返回.gets()函数并不读取换行符'\n',它会吧换行符替换成空字符'\0',作为c语言字符串结束的标志. gets()函数经常和puts()函数配对使用,puts

  • 详解go语言 make(chan int, 1) 和 make (chan int) 的区别

    遇到golang channel 的一个问题:发现go 协程读取channel 数据 并没有按照预期进行协作执行. 经过查资料: 使用channel 操作不当导致,channel分 有缓冲区 和 无缓冲区 , 以下是两者的区别. 无缓冲区channel 用make(chan int) 创建的chan, 是无缓冲区的, send 数据到chan 时,在没有协程取出数据的情况下, 会阻塞当前协程的运行.ch <- 后面的代码就不会再运行,直到channel 的数据被接收,当前协程才会继续往下执行.

随机推荐