函数宏介绍 函数宏,即包含多条语句的宏定义,其通常为某一被频繁调用的功能的语句封装,且不想通过函数方式封装来降低额外的弹栈压栈开销。...\n"); printf("var_a = %d, var_b = %d\n", var_a, var_b); // var_a = 2, var_b = 1 return 0; } C 语言规定...4. ({}) 方式 ({}) 为 GNU C 扩展的语法,非 C 语言的原生语法。...({}) 毕竟不是 while 循环,不能直接使用 break退出函数宏是比较容易理解。那支持返回值是什么意思呢? 答案是 C 语言规定 ({}) 中的最后一条语句的结果为该双括号体的返回值。...缺点:不支持提前退出函数宏;非 C 的原生语法,编译器可能不支持。 5.
一、#define的基本语法 在C语言中,常量是使用频率很高的一个量。常量是指在程序运行过程中,其值不能被改变的量。常量常使用#define来定义。...宏是一种将一系列命令组织在一起,作为一个单独命令来完成特定任务的方式。在编译语言中,宏展开是在编译时进行的,编译器会自动将宏替换为一系列指令。宏展开器是用于执行宏展开的工具。...除了编译语言中的宏,宏这个概念也被广泛应用于其他环境中,比如键盘宏和宏语言。键盘宏是将一系列小命令或动作转化为一系列指令,以简化日常工作。...Word使用宏语言Visual Basic将宏作为一系列指令来编写。 Excel办公软件自动集成了“VBA”高级程序语言,用此语言编制出的程序就叫“宏”。...宏有时候可以做函数做不到的事情。比如:宏的参数可以出现类型,但是函数做不到。
不带参数的宏的定义方式如下(这也是我们经常用到的宏定义) #define 宏名 字符串 //没有分号,说没有分号倒不如说最好不要加分号 这里说下原因吧:因为宏定义它并不是C语言的语句,所以不用加分号...宏名实际上就是一个标识符,必须要符合C语言当中标识符的语法规定的。 标识符的规则:字母、数字、下划线,不以数字开头,注意:关键字不能作为标识符!...注意:宏的参数是先完成替换的,不是先计算然后再进行传参的。...命名事项 相信有些小伙伴已经发现了这个函数的宏的使用语法和函数是非常类似滴。所以语言本身就会没办法帮我们区分二者的一些使用。...那么我们平时写宏或者函数的时候的习惯是↓ 宏明全部大写形式。 函数明不要全部大写,建议第一个字母大写。
宏替换仅仅是简单的替换,它不会影响运算符优先级的,比如: #define DOUBLE(x) x+x int i = DOUBLE(5)*5; printf("%d", i); 相当于i=5+5*5。
宏(Macro, 巨集),是一种批处理的称谓。 计算机科学里的宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式。解释器或编译器在遇到宏时会自动进行这一模式替换。...计算机语言如C语言或汇编语言有简单的宏系统,由编译器或汇编器的预处理器实现。C语言的宏预处理器的工作只是简单的文本搜索和替换,使用附加的文本处理语言如M4,C 程序员可以获得更精巧的宏。...Lisp类语言如Common Lisp和Scheme有更精巧的宏系统: 宏的行为如同是函数对自身程序文本的变形,并且可以应用全部语言来表达这种变形。...一个 C 宏可以定义一段语法的替换,然而一个 Lisp 的宏却可以控制一节代码的计算。 获得了控制代码的执行顺序(见惰性计算和非限制函数)的能力,使得新创建的语法结构与语言内建的语法结构不可区分。...但由上面的定义,它完全不是一种宏语言。然而,它的功能已经从中发展并最终替代了用户应用程序的宏思想,所以它被广泛地错误地称为是一种宏语言。 VBA可以访问许多操作系统函数并支持文档打开时自动执行宏。
今天分享C语言中的两个宏,这两个宏包含了指针和结构体的知识,非常具有代表性。另外,这个题目曾经是大疆无人机的一道笔试题,可见,这两个宏对C语言基础还是有一定要求的。...废话不多说,今天要说的两个宏分别是offsetof和container_of,第一个宏是用来计算结构体中某个成员相对于结构体的偏移量,第二个宏是已知指向结构体某个成员的指针,来计算结构体的指针。...我们知道,C语言给我们提供了一个很好的方式去访问结构体成员,比如结构体变量我们可以用点.去访问,结构体指针我们可以用->去访问,这两种访问方式本质上是通过指针进行访问的,只不过这个过程是编译器帮我们处理了...,还要知道变量类型,所以C语言帮我们考虑了这一点,使用简单的点的方式就行了。...既然C语言帮我们做了计算偏移量这件事情,那我们是不是可以反过来利用一下它,先通过点的方式访问变量,再对变量进行取地址运算,减去结构体首地址不就是变量的偏移量了吗?
C语言宏定义技巧(常用宏定义) 写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等。下面列举一些成熟软件中常用得宏定义。...) ( ((c) >= 'a' && (c) <= 'z') ?...((c) - 0x20) : (c) ) 13、判断字符是不是10进值的数字 #define DECCHK( c ) ((c) >= '0' && (c) <= '9') 14、判断字符是不是16...进值的数字 #define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||\ ((c) >= 'A' && (c...加多一层中间转换宏. 加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数.
函数宏介绍 函数宏,即包含多条语句的宏定义,其通常为某一被频繁调用的功能的语句封装,且不想通过函数方式封装来降低额外的弹栈压栈开销。...利用该特性,可以为函数宏添加参数检测。...4. ({ }) 方式 ({}) 为 GNU C 扩展的语法,非 C 语言的原生语法。...答案是 C 语言规定 ({}) 中的最后一条语句的结果为该双括号体的返回值。...缺点:不支持提前退出函数宏;非 C 的原生语法,编译器可能不支持。 5.
内置函数有许多,可以参考《C语言标准库函数大全.chm》 1.2、自定义函数 1.2.1、函数定义语法 函数类型 函数名(类型 参数名,类型 参数名......,了解指针有助于更加深刻理解C语言。...int arrays[3]={1,2,3}; int (*ptr)[3]; ptr=&arrays; printf("%d\n",**ptr+3); //指向地址的地址 三、宏 C语言中提供的宏定义命令...3.1、简单宏定义 [#define指令(简单的宏)] #define 标识符替换列表 替换列表是一系列的C语言记号,包括标识符、关键字、数、字符常量、字符串字面量、运算符和标点符号。...这些参数可以在替换列表中根据需要出现任意次。 在宏的名字和左括号之间必须没有空格。如果有空格,预处理器会认为是在定义一个简单的宏,其中(x1,x2,…,xn)是替换列表的一部分。
在上篇文章里面,我们分析了预处理的一个完整过程,这能够让我们理解一个写好的程序,在生成一个可执行文件,到底发生了什么,对我们在大型工程项目里面有助于对程序的理解;今天我们继续接着上篇文章的基础上,来分享有关c语言里面关于宏定义的用法...第二部分为宏(macro),一般为缩略语,其名称(宏名)一般大写,而且不能有空格,遵循C变量命令规则。第三部分“替换文本”可以是任意常数、表达式、字符串等。...在预处理工作过程中,代码中所有出现的“宏名”,都会被“替换文本”替换。这个替换的过程被称为“宏代换”或“宏展开”(macro expansion)。“宏代换”是由预处理程序自动完成的。...在C语言中,“宏”分为两种:无参数 和 有参数(这里有参数先不举例子,下面具体分析的话,读者可以详细看到示例来理解这个)。.../a.out c = -1272947832. c = 4. 总结:宏和函数各有千秋,各有优劣。
简单宏定义 简单的宏定义有如下格式: [#define指令(简单的宏)] #define 标识符替换列表 替换列表是一系列的C语言记号,包括标识符、关键字、数、字符常量、字符串字面量、运算符和标点符号...虽然简单的宏常用于定义常量名,但是它们还有其他应用。 4) 、可以对C语法做小的修改。实际上,我们可以通过定义宏的方式给C语言符号添加别名,从而改变C语言的语法。...预处理器不会检查宏参数的类型,也不会进行类型转换。 3) 、无法用一个指针来指向一个宏。如在17.7节中将看到的,C语言允许指针指向函数。这一概念在特定的编程条件下非常有用。...这里还有个问题,如果我们是用宏来创建多个max函数,程序将无法编译。(C语言不允许在同一文件中出现两个同名的函数。)为了解决这个问题,我们是用##运算符为每个版本的max函数构造不同的名字。...上面提到了两种将宏定义为空的定义方式,看上去一样,实际上只要明白了宏都只是简单的代码替换就知道该如何选择了。 8. 预定义宏 在C语言中预定义了一些有用的宏, 见表预定义宏。
首先来理解下宏变量: Java中,一个用final定义的变量,不管它是类型的变量,只要用final定义了并同时指定了初始值,并且这个初始值是在编译时就被确定下来的,那么这个final变量就是一个宏变量。...编译器会把程序所有用到该变量的地方直接替换成该变量的值,也就是说编译器能对宏变量进行宏替换。...如: final String a = "hello"; final String b = a; final String c = getHello(); a在编译期间就能确定下来,而b、c不行,所以a...是宏变量,b、c不是。...所以,再回到上面的程序,finalWorld2和finalWorld4是final定义的,也是在编译期间能确定下来的,所以它能被宏替换,编译器就会让finalWorld2和finalWorld4指向字符串池中缓存的字符串
一个经典的使用场景: 使用offsetof宏,根据已知的一个已经分配空间的结构体对象指针a中的某个成员b的地址,来获取该结构体指针对象a地址。...offsetof_test.c -o offsetof_test.o gcc -o main offsetof_test.o ..../main 运行结果: 函数print_offsetof实现中,主要使用了 offsetof宏定义来获取一个结构体中的各个成员相对于结构体首地址的偏移量 根据结构体定义,不难理解上述输出的结果。...offsetof_test.c -o offsetof_test.o gcc -o main offsetof_test.o ....如果将fullname_ptr转换为(int *)类型,这样再减4的时候,会在0x8fde00c的基础上,减掉16个字节。
适用场景 如果 函数执行时间 小于 函数调用(参数压栈,栈帧开辟与回收,结果返回),那使用宏或者inline能减少函数执行时间。...宏定义与inline函数异同 异:宏定义就是字符替换,不做类型检查;inline反之,相当于不用执行函数调用直接执行函数体。 同:宏和Inline函数的展开发生在预处理阶段。...预处理:简言之,将头文件,宏,inline函数展开,生成.i文件。 inline函数与成员函数 编译器可能会将 类中声明并定义的成员函数 自动转化为内联函数。...参考 待 inline构造函数 与 参数列表 比较
前两天上课,被JAVA老师问懵了,老师问:“你们学C语言,有没有写过带参的宏玩一玩”,说实话,我根本没听过什么带参的宏,我只用过宏定义,所以我下来一定要找个时间把这“带参的宏搞懂”,于是就有了这篇文章...C语言中宏定义分两种,无参的宏和有参的宏 1.无参数的宏 无参数宏定义的一般形式为: #define name value//name是你起的名字,就跟起函数名一样,value是你要给这个名字赋予什么值...(注释与字符串常量除外)均用值替换。... cout<<a<<" "<<b<<endl;//3 5 cout<<c<<" "<<d;//5 3 return 0; } 你会发现函数,并没有交换实参...下面给出带参的宏和函数的区别: 1. 宏会在编译器在对源代码进行编译的时候进行简单替换,不会进行任何逻辑检测,即简单代码复制而已。 2.
,就像真正的函数那样。...(x+1)); print(COUNT(++X)); //结果输出:11 和42 而不是函数的输出36 注意: 预编译器只是进行简单的文本替换,COUNT(x+1)被替换成COUNT(x+1x+1...feral) foo(wolf); else bin(wolf); 判断语言被扩展成: if (!...尽量避免在局部范围内(如函数内、类型定义内等)定义宏,除非它只在该局部范围内使用,否则会损害程序的清晰性。...+/C语言第3版 https://www.cnblogs.com/southcyy/p/10155049.html
我们在使用C语言编写程序的时候,常常会使用到宏定义以及宏编译指令,有的可能比较常用,有的可能并不是很常用,是不是所有的C语言宏定义以及宏指令你都清楚呢?...取消已定义的宏 #if 如果给定条件为真,则编译下面代码 #ifdef 如果宏已经定义,则编译下面代码 #ifndef...#运算符 出现在宏定义中的#运算符把跟在其后的参数转换成一个字符串。 ##运算符 用于把参数连接到一起。预处理程序把出现在##两侧的参数合并成一个符号。...FILE__ 包含当前程序文件名的字符串 __LINE__ 表示当前行号的整数 __DATE__ 包含当前日期的字符串 __STDC__ 如果编译器遵循ANSI C标准...,它就是个非零值 __TIME__ 包含当前时间的字符串 另外在GCC下面,还有如下的宏定义: __FUNCTION__ 表示当前的函数名 __VA_ARGS__ 表示可变参数输入
1.这个函数在遇到\0的时候并不会停下来 2.如果source和destination有任何的重叠,复制的结果都是未定义的 memcpy函数最终返回的是目标空间的起始地址 //函数的一种写法: 这个函数最终返回的是目标空间的起始地址...: //函数的一种写法: //这个函数最终返回的是目标空间的起始地址 void* my_memcpy(void *dest, const void*src, size_t num) { assert...,非要使用,结果就是未定义的 //只负责不重叠的内存 函数的返回值是void*类型的数据 这个memcpy函数有三个数据 2.memmove--内存移动--使用和模拟实现 2.memmove--内存移动...//总之:这个拷贝是分三块区域的,最前面的一块区域满足dest<src //我们只能从前往后进行拷贝,不然会出错误 //而剩下的两块区域可以同时从后往前进行拷贝,那么我们就将这两块区域放在一起 在C语言标准中...,明确规定了memcpy只要能实现不重叠的拷贝就行,重叠的拷贝交给memmove 我们发现vs上面的库函数memcpy函数也能实现重叠内存的拷贝 我们在以后的拷贝中,我们可以用memmove,因为不管是重叠的还是不重叠的都能搞定
请看下面这段代码: 这是我早期做intel驱动的时候看到intel的驱动工程师写的代码,虽然这两个宏没有实际用途,但细细一看却发现大有用处。
第一时间看干货文章 1 C语言中,宏是在预编译时用宏体内容“文本替换”代码中的宏名的。...先讲一些宏嵌套的展开规则: 一般的展开规律像函数的参数一样:先展开参数,再分析函数,即由内向外展开; 当宏中有#运算符的时候,不展开参数; 当宏中有##运算符的时候,先展开函数,再分析参数; ##运算符用于将参数连接到一起...整个宏体内容未加括号包裹起来 #define T(x) x+1 cout << 10*T(1) << endl; //输出 11 而非20 解决办法: 在宏定义中,将参数加上括号,这样在替换时保证括号内的表达式优先运算...利用括号将整个宏定义的内容括起来,保证整个宏定义中的表达式优先运算。 宏嵌套: 宏嵌套是宏使用的难点,也是易错点。...往期推荐 分享一个开源的QT的串口示波器 C语言回调函数,提升C技巧必备 用C语言实现状态机设计模式 stm32可以跑Linux操作系统吗?
领取专属 10元无门槛券
手把手带您无忧上云