首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

替换、条件编译、头文件展开

替换、文件编译和头文件的展开 程序执行的几个步骤: 1.预处理: ①将头文件展开替换 ③条件编译 ④去掉注释 2.编译: ①语义语法纠错 ②将.c文件编译成汇编语言 3.汇编:将汇编语言变成二进制机器语言...#error // 停止编译并显示错误信息 的定义 #define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为或定义。...这样,定义参数和#define定义可以包含其他#define定义的符号。但是,不可以出现递归。...FBI_WARNING printf("Unknown\n"); #else printf("NO\n"); #endif } return 0; } 头文件的展开...①#include指令使另外一个文件被编译:预处理器删除这条指令,并用包含文件的内容替换。

2.1K20

C语言 嵌套的展开规则

先讲一些嵌套的展开规则: 一般的展开规律像函数的参数一样:展开参数,再分析函数,即由内向外展开; 当中有#运算符的时候,不展开参数; 当中有##运算符的时候,展开函数,再分析参数; ##运算符用于将参数连接到一起...例如: #define T(x) x##[2] int a[5] = {1,2,3,4,5}; cout << T(a) << endl; //输出 3 即 a[2] 的常见展开错误: // 1....下面我将嵌套的展开规则用流程图来说明一下: 注意:上图中的 2 和 3 是条件或,只要满足一个条件就会进入流程 5。...,PARAM名被破坏了,变成了a_PARAM不再是有效的名了 -> 展开 ADDPARAM:TO_STRING(a_PARAM(INT_1)) -> 展开 TO_STRING:TO_STRING1(...a_PARAM(INT_1)) -> 展开 TO_STRING1:"a_PARAM(INT_1)" 注意:嵌套展开规则与编译器有关,不同的编译器可能对同一个嵌套展开不同。

1.3K20
您找到你想要的搜索结果了吗?
是的
没有找到

图解 Rust 编译器与语言设计 | Part1:Rust 编译过程与展开

Rust 展开 Rust 本质上存在两类:声明(Declarative Macros) 与 过程(Procedural Macros) 。...在这个过程中,如果遇到了宏代码(不管是声明还是过程),则会使用专门的「解释器(Macro Parser)」 来解析宏代码,将宏代码展开为 TokenStream,然后再合并到普通文本代码生成的 TokenSteam...你可能会有疑问,其他语言的都是直接操作 AST ,为什么 Rust 的在 Token 层面来处理呢?...所以后来 Rust 引入了过程。过程允许你在展开过程中进行任意计算。但我们不是说,Rust 没有暴露 AST API 吗?为什么过程可以做到这么强大?...理解过程展开原理,将有助于你学习过程。 小结 本篇文章主要介绍了 Rust 代码的编译过程,以及 Rust 宏代码的展开机制,学习这些内容,将有助于你深入理解 Rust 的概念。

5K31

C++ #define详解

#define 的作用 在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为“”。被定义为“”的标识符称为“名”。...在编译预处理时,对程序中所有出现的“名”,都用定义中的字符串去代换,这称为“代换”或“展开”。定义是由源程序中的定义命令完成的。代换是由预处理程序自动完成的。...在C或C++语言中,“”分为有参数和无参数两种。 无参定义 无参名后不带参数。 其定义的一般形式为: #define 标识符 字符串 其中的“#”表示这是一条预处理命令。...在编写源程序时,所有的(a+b)都可由M代替,而对源程序作编译时,将先由预处理程序进行代换,即用(a+b)表达式去置换所有的名M,然后再进行编译。...带参定义 c语言允许带有参数。在定义中的参数称为形式参数,在调用中的参数称为实际参数。对带参数的,在调用中,不仅要展开,而且要用实参去代换形参。

1.7K10

rust声明式

这就是某些地方提到的“Hygienic Macros”(有些地方也翻译为卫生,翻译的很抽象)。最后一行代码中传入的b+3被当做了一个整体。...如果是在C/C++中,不会自动将表达式作为整体,而是直接进行字符串替换。而 Rust 编译器会自动处理变量名和作用域,确保展开后的代码不会引入未预料的变量冲突。下面是一个C/C++中使用的例子。...因此,我们在 C/C++ 中编写要特别注意,参数在使用的时候必须加上括号。现在我们来修复上面 C/C++ 代码中的。...// 而 C/C++不强制要求,但是如果遇到代码片段,在 C/C++ 中也应该使用{}包裹起来。...不利于错误检查:展开发生在编译期间,因此错误信息可能不够明确和直观,难以定位展开后的具体错误位置。 难以调试:展开过程对于开发者不是透明的,因此在调试过程中可能会遇到难以解决的问题。

29910

C++ 入门基础

- 正文 初识C++ 简单了解下 C++ 的起源 C++祖师爷—本贾尼·斯特劳斯特卢普 ️C++起源 C语言 是结构化和模块化的语言,适合处理较小规模的程序。...<< endl; return 0; } 向世界打个招呼后,我们就可以正式开始 C++ 的修行之路了 ---- 命名空间 命名空间是我们接触的第一个 C++ 特性,当然其他高级语言也支持 背景...,可以使用 全局展开 的方式,因为不受其他人干扰,也不会干扰其他其他场景中,推荐使用 部分展开 + 域作用限定符,频繁使用的对象通过 部分展开,使用频率较少的对象直接使用 域作用限定符 就行了 原因...,因为函数存在很多坑,并且在某些场景下使用复杂 #define ADD(x, y) ((x) + (y)) //通过函数实现ADD,比较复杂、麻烦 除了使用复杂外,还存在以下缺点: 不能进行调试,...是直接进行替换的 没有类型安全检查 在书籍《Effective C++》 中,作者建议 使用 const 和 enum 替换定义的常量 使用内联函数 inline 替换函数 总之,很危险,需要少用

16510

C++之内联函数

既然C语言中有优化这个问题的方法,那么我们的C++为什么还要创造一种新方法呢? 我们先来回顾一下的优缺点: 1.的优缺点 (1)优点 ①增强代码的复用性。 ②提高性能。...2.C++中替代的方法 由于有这三个缺点,C++中给出了替代的方法: (1)常量定义换用const enum (2)短小函数定义换用内联函数 其中的const enum是C语言中就有的,内联函数却是...C++新给出的概念。...二、内联函数 使用inline关键字修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,因此没有函数调用建立栈帧的开销,进而提升程序运行的效率。...(2)区别 因为内联函数的替换过程是在程序运行起来以后,所以可以进行调试,方便观察; 因为内联函数是直接在程序中展开,和其他函数是一样的,所以内联函数的参数类型是受限制的。

56220

C++避坑之#define常量和形似函数的

尽量避免#define定义常量 在C++中,定义常量应该尽量避免使用#define来定义一个常量,主要原因定义只做替换,不做类型检查和计算,不仅没有作用域限制,而且容易产生错误。...因此,在C++中我们尽量避免使用#define来定义一个常量,应使用const和enum来定义常量。 尽量避免形似函数的 #define的另外一个需要注意的地方就是,尽量减少形似函数的使用。...a++ : b);,由于a++在这里是比较再递增,3比0大,因此func的参数为a++,这时候a应先将值传递给func,然后再累加,因此func打出来的结果为4。实际上此时a的值已经变为5。...使用形似函数的有时候的确会给我们带来方便,但有时候在直观上也会带来使用上的歧义,实际上也不是的错,大部分情况是我们把情况简单化、直观化了,实际上如果将其展开并替换后,我们也能及时发现问题,但问题是按照的逻辑再次展开分析...总结 在C++中,尽量避免#define常量和形似函数的使用。对于一些简单的表达式的,要避免嵌套,尽量做到简单,对于嵌套要做好运算符优先级检查和每一层的嵌套隔离,避免歧义的产生。

27810

C++】内联函数、auto关键字、NULL与nullptr

专栏放在【C++知识总结】,会持续更新,期待支持 ---- 内联函数 与内联函数 我们在C语言阶段就学习了关键字#define 用来定义函数、常量),然后在预处理阶段会实现的替换,这样的话不仅大大的提高了代码的复用性...+针对存在的这些缺点,给出了以下应对方法: 用const enum来定义常量 用内联函数来替换短小函数的定义 内联函数的概念 函数前面用关键字inline来修饰的函数,就叫内联函数,编译时C++编译器会在调用内联函数的地方将指令展开...因为inline被展开,就没有函数地址了,链接就会找不到,编译器会报错 总结 内联函数用来弥补替换存在的缺陷,在编译阶段会将指令展开,不会开辟额外栈帧,提高程序效率的同时,也会使目标文件变大,适用于规模小.../int return 0; } 在同一行定义多个变量 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量...auto a = 1, b = 2;//auto对a推导,为int,然后用推导出来的类型来定义b,就是int b=2 auto c = 3, d = 3.5;//error 因为c是int,

40560

【C语言基础】:预处理详解(一)

结果发现打印的是30,预处理之后生成目标文件之后可以发现5会和a相乘,然后再加a,导致结果与我们的出现误差。 这个问题,的解决办法是在定义表达式两边加上⼀对括号就可以了。...参数的展开参数在替换时会展开,这意味着如果参数本身是一个,它也会被展开(替换)。这个过程称为展开展开。...展开的顺序: 当参数中包含其他时,预处理器会按照它们在定义中出现的顺序进行替换。如果A中使用了B,而B又使用了C,那么预处理器首先会替换C,然后是B,最后是A。...展开的深度: 展开的深度是有限的。如果一个展开后仍然是一个(即),这个过程会继续,但是有一个深度限制,以避免无限循环。 定义的顺序: 定义的顺序可能会影响替换的结果。...注意: 参数和 #define 定义中可以出现其他 #define 定义的符号。但是对于,不能出现递归。

12410

iOS中的预编译指令的初步探究

a是1,a++表示使用a的值进行计算,然后再加1。那么其实这个式子想要计算的是取a和b的最小值,然后a等于a加1:所以正确的输出a为2,b为1才对!...我们美化一下这,首先是最后那个__NSMIN_IMPL__内容实在是太长了。我们知道代码的话是可以插入换行而不影响含义的,是否也可以呢?...注意函数必须是有意义的运算,因此你不能直接写AB来连接两个参数,而需要写成例子中的A##B。中还有一切其他的自成一脉的运算符号,我们稍后还会介绍几个。...另外你也不用担心展开以后式子里的NSLog会再次被自己展开,虽然展开式中NSLog也满足了我们的定义,但是展开非常聪明,展开后会自身无限循环的情况,就不会再次被展开了。...也就是说,在这里内容的format指代的其实就是定义的对expression取了两次反?

2.2K80

长文详解:C语言预处理命令

定义表达式: #define M (y*y+3*y) 编码时所有的表达式(y*y+3*y)都可由M代替,而编译时先由预处理程序进行替换,即用(y*y+3*y)表达式去置换所有的名M,然后再进行编译...在C语言中,遇到多个int var则自动认为其中一个是定义,其他的是声明。 (3) C语言和C++语言连接结果不同,可能是在进行编译时,C++语言将全局变量默认为强符号,所以连接出错。...相当于借助_TO_STRING这样的中间展开参数,延迟其字符化。 6.2 其他注意事项 1....即在一处将常量数值定义为其他地方通过引用该,生成自己模块的。严禁相同含义的常量数值,在不同地方定义为不同的,即使数值相同也不允许(维护修改后极易遗漏,造成代码隐患)。 3....但某些编译器(为了调试需要)可将inline函数转成普通函数; 3) 函数的入参没有类型,不安全; 5) inline函数会在目标代码中展开,和的效率一样高; 注意,某些函数用法独特,不能用inline

2.7K10

C++C++入门必备知识详细讲解

1000 个空间,然后再为 n 创建空间,n 这个时候的位置是处于下方的;如果 func 销毁后,如果有新的空间覆盖,这要取决于这个空间是否比原来 func 的空间要大,如果这个空间很大,覆盖了 n...,注意,这里定义的((a)+(b))不能写成(a+b),因为考虑到运算符优先级问题,如ADD(1 | 2 + 1 & 2)这种表达式,加号优先级更高,会执行加的操作,再执行 | 和 & ,并不是我们想要的结果...上面的定义在预处理阶段是直接展开替换,所以没有建立栈帧,很好地提高了效率。...但是给我们带来好处的同时,必然会带来不便,如使用定义会容易出错,就如上面两数相加的,少一个括号都不行,所以的语法坑很多。 最后总结一下的优缺点: 优点: 没有类型的严格限制。...内联函数的概念 所以C++引入了内联函数,以 inline 修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

9610

一张图看懂linux内核中percpu变量的实现

所以不管是c/c++/rust,还是java/c#等,都内置了对thread local变量的支持。...我们不管细节,先来看一张图,这样从全局的角度来了解下它的实现。 ?...this_cpu_read_stable方法其实也是一个,它全部展开后是下面这个样子: ? 在这里,我们不讲展开后各语句到底是什么意思,我们先跑个题。...读过linux内核源码的同学都知道,在linux内核中,使用的非常多,且比较复杂,如果我们对自己进行展开的正确性没有信心的话,可以使用下面我介绍的这个方式,使用它,你可以非常容易的得到任意文件展开后的结果...DEFINE_PER_CPU还是一个,其展开后如下: ? 在展开后的变量定义中,最重要的是指定该变量的section为.data..percpu。

1.8K21

面试官:什么是定义和内联函数?

今天想要分享的是内联函数和定义。在我的某次笔试中也出现过一次。题目大意问的是在C语言和C++中分别用什么来处理一段短小、反复被调用的代码。...我们知道,在调用函数的时候,系统要将程序中的一些状态信息存到栈中,然后再跳转执行,在参数保存和传递的过程中是需要时间和空间的开销,使得效率下降,特别是在频繁地调用函数的时候。...这里使用的是C++,本来想用C的,但是在我的vscode上好像不支持inline,干脆就用C++了。 既然定义和内敛函数都可以完成替换,为什么还要引入内联函数呢?...b=2; cout<<"inline:a+b="<<2*fun(a,b)<<endl; cout<<"sums:a+b="<<2*sums(a,b)<<endl; } 我们的本意是希望<em>先</em>计算...在inline里面,正确计算出了结果6,而<em>宏</em>里面却得到4.因为<em>宏</em><em>展开</em>后是这样的:2*a+b 这样就出现了错误。这是很多初学者容易犯的错误,也是在面试题中的高频考点,至少在我最近的面试题中频繁出现了。

1.5K20

C++打怪升级(三)- 内联函数 、auto、范围for循环

y) ((x) + (y)) 定义之后,出现定义的地方都会在预处理阶段被直接替换,相当于在出现定义的地方展开。...其次没有类型检查,也就不安全,容易出错且不易发现。 C++从C而来,也对C做出了一些改进。那么C++是否选择了C语言的这种采用的方法呢?...---- 内联函数 概念 以关键字inline修饰的函数称为内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,从而内联函数能够提升程序运行的效率。...在链接阶段test.o会到其他目标文件中寻找Add函数大的有效地址。...---- 代替的方式 C++中除了可以用内联函数代替定义之外,还可以使用const常变量、enum常量来代替常量。

46720

嵌入式c编程的一点小记录——

可以验证自己定义、展开是否正确。...另外,vscode是个好工具,集成了C/C++的插件鼠标点击到代码上就可以展开,微软的工具还是说不错的,毕竟“宇宙第一ide”是来自微软的vs。 2、x macro这个技巧已经存在很多年了。...上时间,c语言还未诞生就存在于其他编程语言中了。但是c语言也是有的,应该说是将这个特性引用了。...其中定义添加了可变参数的功能,__VA_ARGS__,网上直接搜索“”可变参数“”,中文英文都很多的,所以这个功能国内开发人员是用的很多的。这里就不展开了。...都知道c++是有模板的,那么c语言的可以模仿c++的模板,至少是简易版本的模板,提高了开发的效率。

47220
领券