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

(译) Understanding Elixir Macros, Part 1 Basics

就我个人而言, 我觉得宏的主题非常有趣, 在本系列文章中, 我将试图解释它们是如何工作的, 提供一些关于如何编写宏的基本技巧和建议....无论是宏还是代码生成, 我们都在编译的过程中对抽象语法树做了某些变换. 为了理解它是如何工作的, 你需要学习一点编译过程和AST的知识....无论是宏还是原地代码生成, 我们都在编译的过程中对抽象语法树 (AST) 做了某些变换. 为了理解它是如何工作的, 你需要学习一点编译过程和 AST 的知识....我们的宏接收到了一个 quoted expression. 这一点非常重要 — 无论你发送了什么参数给一个宏, 它们都已经是 quoted的....展开一个 AST 在 Shell 观察其是如何连接起来是很容易的.

19130

C语言详解(预编译)

4、带有副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果,副作用就是表达式求值的时候出现的永久性效果 例如:...在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号,如果有,它们首先被替换 替换文本随后被插入到程序中原来文本的位置,对于宏,参数名被他们的值所替换 最后,再次对结果文件进行扫描...函数参数只在函数调用的时候求值一次,它的结果值传递给函数,表达式的求值结果更容易预测 带有副作用的参数 参数可能被替换到宏体中的多个位置,如果宏的参数被多次计算,带有副作用的参数求值可能会产生不可预测的结果...函数参数只在传参的时候求值一次,结果更容易控制 参数类型 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用任何参数类型 函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是相同的...通过学习预编译过程,可以了解如何使用条件编译来实现跨平台编译,提高代码的可移植性。

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

    C语言三剑客之《C陷阱与缺陷》一书精华提炼

    C程序被两次划分为记号,首先是预处理器读取程序,它必须对程序进行记号划分以发现标识宏的标识符。通过对每个宏进行求值来替换宏调用,最后,经过宏替换的程序又被汇集成字符流送给编译器。...2、句法缺陷 理解这些记号是如何构成声明、表达式、语句和程序的。 2.1 理解声明 每个C变量声明都具有两个部分:一个类型和一组具有特定格式的、期望用来对该类型求值的表达式。...当我们知道如何声明一个给定类型的变量以后,就能够很容易地写出一个类型的模型(cast):只要删除变量名和分号并将所有的东西包围在一对圆括号中即可。...4 语义缺陷 4.1 表达式求值顺序 一些C运算符以一种已知的、特定的顺序对其操作数进行求值。但另一些不能。例如,考虑下面的表达式: a 求值。...:运算符中的三个操作数:a、b和c,最先对a进行求值,之后仅对b或c中的一个进行求值,这取决于a的值。,运算符首先对左边的操作数进行求值,然后抛弃它的值,对右边的操作数进行求值[8]。

    1.5K10

    深入浅出 Babel 下篇:既生 Plugin 何生 Macros

    这是一个通用的宏展开器,不仅可以用于 C,也可以用于其他语言和文本文件的处理(参考这篇有趣的文章:《使用 GNU m4 为 Markdown 添加目录支持》), 关于m4可以看让这世界再多一份 GNU...这种数据即程序、程序即数据的概念,使得Lisp可以轻松地自定义宏. 不妨来看一下Lisp定义宏的示例: ; 使用defmacro定义一个nonsense宏, 接收一个function-name参数....其语法类似于const或者let。...不过不建议这么做,宏不应该假定其被展开的上下文: syntax swap = (ctx) => { // ......如何被应用?何时被应用?而且通常你还需要和其他工具链的配合,例如ESlint、Typescript声明等等。Macro 由代码显式地应用,我们更明确它被应用的目的和时机,对源代码的侵入性最小。

    1.5K31

    C语言预处理详解

    #define DOUBLE( x) ( ( x ) + ( x ) ) 提⽰: 所有⽤于对数值表达式进⾏求值的宏定义都应该⽤这种⽅式加上括号,避免在使⽤宏时由于参数中的 操作符或邻近操作符之间不可预料的相互作...带有副作⽤的宏参数 当宏参数在宏的定义中出现超过⼀次的时候,如果参数带有副作⽤,那么你在使⽤这个宏的时候就可 能出现危险,导致不可预测的后果。副作⽤就是表达式求值的时候出现的永久性效果。...宏替换的规则 在程序中扩展#define定义符号和宏时,需要涉及⼏个步骤。 1. 在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。如果是,它们⾸先 被替换。 2....__DEBUG__注释掉  #ifdef和#endif是一对(一起使用)  #ifdef就像一个开关一样我们想让他参与编译就让他参与,不想让他参与就不参与编译。...如何解决头⽂件被重复引⼊的问题?答案:条件编译。

    8510

    校长讲堂第十讲

    预处理器 运行的程序并不是我们所写的程序:因为 C 预处理器首先对其进行了转换。出于两个主要原因(和很多次要原因),预处理器为我们提供了一些简化的途径。...例如,putchar()和 getchar()通常实现为宏以避免对每一个字符的输入输出都要进行函数调用。 6.1 宏不是函数 由于宏可以象函数那样出现,有些程序员有时就会将它们视为等价的。...注意第一个参数完全可以使用如*z++之类的东西,尽管它在宏中两次出现,但只会被求值一次。...而第二个参数会被求值两次(在宏体中,x 出现了两次,但由于它的两次出现分别在一个:的两边,因此在putc()的一个实例中它们之中有且仅有一个被求值)。...由于 putc()中的文件参数可能带有副作用,这偶尔会出现问题。不过,用户手册文档中提到:“由于 putc()被实现为宏,其对待 stream 可能会具有副作用。

    34361

    【C】程序环境和预处理

    return 0; } ---- #和## #的作用 使用#, 可以把一个宏参数变成对应的字符串。 如何把参数插入到字符串中?...否则其结果就是未定义的。 带副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能 出现危险,导致不可预测的后果。...函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测。 带有副作用的参数 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果。...函数参数只在传参的时候求值一次,结果更容易控制。 参数类型 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型。...结语: 这里我们关于前半部分的内容就介绍完了,后半部分马上会更 文章中某些内容我们之前有介绍,所以只是一笔带过,还请谅解。 希望以上内容对大家有所帮助,如有不足望指出

    19330

    详解程序的预处理与编译与连接

    3.2.3 #define 替换规则 在程序中扩展#define定义符号和宏时,需要涉及几个步骤。 1.在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。...对于宏,参数名被它们的值所替换。 3.最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号,如果是,就重复上述处理过程。...3.2.4 #和## 提问 如何把参数插入到字符串中?...3.2.5 带副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。...表达式的求值容易预测 带有副作用的参数 参数可能被替换到宏中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果 函数参数只在传参的时候求值一次,结果更容易控制。

    7510

    程序环境和预处理

    2.2.3 #define 替换规则 在程序中扩展#define定义符号和宏时,需要涉及几个步骤。 1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。...对于宏,参数名被他们的值所替换。 3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。 注意: 1....(字符串常量中的内容不会被替换) 3.2.4 #和## 如何把参数插入到字符串中?...否则其结果就是未定义的。 3.2.5 带副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。...带 有 副 作 用 的 参 数 参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果。 函数参数只在传参的时候求值一 次,结果更容易控制。

    8410

    【C语言】什么是宏定义?(#define详解)

    编译器会在编译期间对所有的常量表达式(只包含常量的表达式)求值,预处理器不做计算,不对表达式求值,它只进行替换. ​...但唯一例外的是双引号中的宏,如: 这时因为第二个宏X被双引号引起来了,导致其不被编译器识别为宏,而识别为一个没有特殊含义的字符串了....通过指定结构体类型和成员名称作为参数,offsetof宏会返回该成员在结构体中的偏移量。 (不懂如何计算结构体成员偏移量的可以移步我的这篇博客:【C语言】结构体的大小是如何计算的?...函数参数只在函数调用的时候求 值一次,它的结果值传递给函 数。表达式的求值结果更容易预 测。...带 有 副 作 用 的 参 数 参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果。 函数参数只在传参的时候求值一 次,结果更容易控制。

    66610

    抽丝剥茧C语言(高阶)程序环境和预处理

    替换规则 在程序中扩展#define定义符号和宏时,需要涉及几个步骤。 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。...对于宏,参数名被他们的值所替换。 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。 注意: 4....否则其结果就是未定义的。 宏和函数对比 属性 #define定义宏 函数 代码长度 每次使用时,宏代码都会被插入到程序中。...,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号 函数参数只在函数调用的时候求值一次,它的结果值传递给函数。...表达式的求值结果更容易预测 带有副作用的函数 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果 函数参数只在传参的时候求值一次,结果更容易控制 参数类型 宏的参数与类型无关

    53500

    C语言预处理超详解

    带有副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。 副作用就是表达式求值的时候出现的永久性效果。...对于宏,参数名被它们的值所替换。 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。...带有副作用的参数 参数可能被替换到宏体中的多个位置,如果宏的参数被多次计算,带有副作用的参数求值可能会产生不可预料的结果。...函数参数只在传参时求值一次,结果更容易控制 参数类型 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型。...一个头文件被包含10次,那就实际被编译10次,如果重复包含,对编译的压力就比较大。 如何解决头文件被重复引入的问题? 答案是条件编译。

    10310

    【程序的编译(预处理操作)+链接】

    3.2.3 #define 替换规则 在程序中扩展#define定义符号和宏时,需要涉及几个步骤。 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。...对于宏,参数名被他们的值所替换。 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。...3.2.4 #和## 如何把参数插入到字符串中?...函数参数只在函数调用的时候求值一次,它的结果值传递给函数,表达式的求值结果更容易预测。 带有副作用的参数 参数可能被替换到宏体的多个位置,所以带有副作用的参数求值可能会产生不可预料的后果。...函数参数只在传参的时候求值一次,结果更容易控制。 参数类型 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型。

    55700

    C++的constexpr

    constexpr是C++11引入的关键字,用于定义在编译时求值的常量表达式。它可以修饰函数、对象和模板参数,并要求其在编译时就能够得到计算结果。...宏替代:使用constexpr可以取代宏,在编译时执行计算和逻辑操作,避免了宏带来的一些问题(如类型安全性和可读性)。...constexpr int value = 42; ②声明函数 通过在函数声明中使用constexpr关键字,可以指示编译器在编译时对函数进行求值,并在需要时将其结果作为常量使用。...int y; constexpr Point(int a, int b) : x(a), y(b) {} }; constexpr Point p(3, 4); // 在编译时初始化对象p,其成员...x为3,y为4 ④用于模板参数 在C++14中,constexpr可以用于模板参数,以允许在编译时进行模板实例化。

    23920

    【C语言】程序的编译、预处理

    在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。...对于宏,参数名被他们的值所替换。 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。...符 优 先 级 宏参数的求值是在所有周围表达式的上下文环境里, 除非加上括号,否则邻近操作符的优先级可能会产生 不可预料的后果,所以建议宏在书写的时候多些括 号。...带 有 副 作 用 的 参 数 参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果。 函数参数只在传参的时候求值一 次,结果更容易控制。...#define __TEST_H__ //头文件的内容 #endif //__TEST_H__ //或者 #pragma once 这样就可以就可以避免头文件的重复引入 至于其他预处理指令,如果大家对其感兴趣的化可以查找查找资料看一看

    28420

    CC++中----->#define定义函数和自定义函数各方面比较

    #define宏:宏参数的求值是在所有周围表达式的上下文环境里,除非它们加上括号,否则邻近操作符的优先级可能产生不可预料的结果。...函数:函数参数只在函数调用时求值一次,它的结果值传递给函数。表达式的求值结果更容易预测。...参数求值 #define宏:参数用于宏定义时,每次都将重新求值,由于多次求值,具有副作用的参数可能会产生不可预测的结果。...函数:参数在函数调用前只求值一次,在函数中多次使用参数并不会导致多次求值过程,参数的副作用并不会造成任何特殊问题。...总的来说#define定义函数优缺点如下: 优点:可完成函数调用的功能,对输入参数没有限制,又能减少系统开销,提高运行效率。因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行。

    1.5K20

    Jmeter(五) - 从入门到精通 - 创建网络计划实战和创建高级Web测试计划(详解教程)

    1.简介   上一篇中宏哥已经将其的理论知识介绍了一下,这一篇宏哥就带着大家一步一步的把上一篇介绍的理论知识实践一下,然后再说一下如何创建高级web测试计划。...这里HTTP信息头管理器,主要添加一个参数User-Agent。根据你抓包的header来填写即可。 ? 4.选中线程组,设置一个http,发送http默认请求值,放入你需求测试的地址。...宏哥本地搭建的Jenkins应用程序,那么Read请求值,我们查看抓到登录请求包(2.2.1)就很清楚了,这里请求值填写如下: (1)protocol(协议:http or https):目前这个是本地搭建的...4、查看Jenkins的新建任务,没有看到“北京-宏哥”,说明删除成功了,如下图所示: ? 3.制定高级Web测试计划 在本小节中,红儿将介绍一下如何创建高级 测试计划来测试网站。...图2-请求参数 3.2使用标题管理器 该HTTP头管理器可以让你定制什么样的信息JMeter的HTTP请求头发送。此标头包含“用户代理”,“编译指示”,“推荐人”等属性。

    3.7K30

    Theano 中文文档 0.9 - 7.2.3 Theano中的导数

    计算梯度 现在让我们使用Theano来完成一个稍微复杂的任务:创建一个函数,该函数计算相对于其参数x的某个表达式y的导数。为此,我们将使用宏T.grad。例如,我们可以计算 相对于 的梯度。...Theano实现theano.gradient.jacobian()宏,执行计算Jacobian所需的所有内容。以下内容说明如何手动执行。...为了手动计算某些函数y相对于某个参数x的雅可比矩阵,我们需要使用scan。我们所做的是循环y中的条目,并计算y [i]相对于x的梯度。...注意 v是求值的关键点,其在L操作和R操作中不同。对于L操作符,这个求值的关键点需要具有与输出相同的形状,而对于R操作符,该点应具有与输入相同的形状参数。此外,这两个操作的结果不同。...注意 v是求值的关键点,其在L操作和R操作中不同。对于L操作符,这个求值的关键点需要具有与输出相同的形状,而对于R操作符,该点应具有与输入相同的形状参数。此外,这两个操作的结果不同。

    62230

    【C语言】预处理详解(上)

    也就是说,先前的printf里的参数变为了 printf("%d",a+1*a+1); 这样说的话就比较清晰了,有替换产生的表达式并没有按照我们的预期顺序进行运算求值。...这里还有一个宏定义: #define DOUBLE(x) (x) + (x) 在定义中我们为了避免预算符之间的优先级和结合性,我们给其添上了括号,但是这个宏仍然会出现问题。...当宏参数在宏的定义中出现超过一次的情况,如果参数带有副作用,那么你在使用这个宏的时候就有可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性的效果。...宏替换的规则 在程序中扩展使用#define定义符号和宏,需要涉及几个步骤: 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果有,它们首先被替换。...对于宏来说,参数名被它们的值所替代。 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果有则重复上述步骤。

    11110

    宏与WINDOWS API简单使用

    int c = MAX(a, b); cout << c << endl; } 预编译指令 程序的编译过程可以分为预处理、编译、汇编三部分,其中预处理是首先执行的过程,预处理过程扫描程序源代码,对其进行初步的转换...整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。 单纯一个#号表示空指令,没有任何作用。...#line指令可以重新设定这两个变量的值,其语法格式为 #line number[“filename”] 其中第二个参数文件名是可省略的,并且其指定的行号在实际的下一行语句才会发生作用。...pragma message 该指令能够让编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。...*LPCUWSTR, *PCUWSTR; 是一个LPCWSTR和PCTSTR类型,是一个WCHAR类型参数 _NullNull_terminated 宏的含义 宏是一个头部注解,藐视了一些类型.如何用作函数的参数以及返回值

    86310
    领券