宏定义中#等的用法

合集下载

C语言宏定义#define

C语言宏定义#define

C语言宏定义#define一、数值宏常量#define 宏定义是个演技非常高超的替身演员,但也会经常耍大牌的,所以我们用它要慎之又慎。

它可以出现在代码的任何地方,从本行宏定义开始,以后的代码就就都认识这个宏了;也可以把任何东西定义成宏。

因为编译器会在预编译的时候用真身替换替身,而在我们的代码里面却又用常常用替身来帮忙。

看例子:#define PI 3.141592654在此后的代码中你尽可以使用PI 来代替3.141592654,而且你最好就这么做。

不然的话,如果我要把PI 的精度再提高一些,你是否愿意一个一个的去修改这串数呢?你能保证不漏不出错?而使用PI 的话,我们却只需要修改一次。

这种情况还不是最要命的,我们再看一个例子:#define ERROR_POWEROFF -1如果你在代码里不用ERROR_POWEROFF 这个宏而用-1,尤其在函数返回错误代码的时候(往往一个开发一个系统需要定义很多错误代码)。

肯怕上帝都无法知道-1 表示的是什么意思吧。

这个-1,我们一般称为“魔鬼数”,上帝遇到它也会发狂的。

所以,我奉劝你代码里一定不要出现“魔鬼数”。

第一章我们详细讨论了const 这个关键字,我们知道const 修饰的数据是有类型的,而define 宏定义的数据没有类型。

为了安全,我建议你以后在定义一些宏常数的时候用const代替,编译器会给const 修饰的只读变量做类型校验,减少错误的可能。

但一定要注意const修饰的不是常量而是readonly 的变量,const 修饰的只读变量不能用来作为定义数组的维数,也不能放在case 关键字后面。

二、字符串宏常量除了定义宏常数之外,经常还用来定义字符串,尤其是路径:A),#define ENG_PA TH_1 E:\English\listen_to_this\listen_to_this_3B),#define ENG_PATH_2 “E:\English\listen_to_this\listen_to_this_3”噢,到底哪一个正确呢?如果路径太长,一行写下来比较别扭怎么办?用反斜杠接续符啊:C), #define ENG_PA TH_3 E:\English\listen_to_this\listen\_to_this_3还没发现问题?这里用了4 个反斜杠,到底哪个是接续符?回去看看接续符反斜杠。

C语言中的三种预处理功能

C语言中的三种预处理功能

C语言中的三种预处理功能C语言中的三种预处理功能导语:预处理指令是以#号开头的代码行。

#号必须是该行除了任何空白字符外的第一个字符。

#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。

整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。

下面是C语言三种预处理功能,欢迎阅读:指令用途# 空指令,无任何效果#include 包含一个源代码文件#define 定义宏#undef 取消已定义的宏#if 如果给定条件为真,则编译下面代码#ifdef 如果宏已经定义,则编译下面代码#ifndef 如果宏没有定义,则编译下面代码#elif 如果前#if条件不为真,当前条件为真,则编译下面代码,其实就是else if的简写#endif 结束一个#if……#else条件编译块#error 停止编译并显示错误信息特殊符号预编译程序可以识别一些特殊的符号。

预编译程序对于在源程序中出现的这些串将用合适的值进行替换。

注意,是双下划线,而不是单下划线。

FILE 包含当前程序文件名的字符串LINE 表示当前行号的整数DATE 包含当前日期的字符串STDC 如果编译器遵循ANSI C标准,它就是个非零值TIME 包含当前时间的字符串//例#includeint main(){printf("Hello World! ");printf("%s ",__FILE__);printf("%d ",__LINE__);return 0;}1. 宏定义不带参数宏定义又称为宏代换、宏替换,简称“宏”。

预处理(预编译)工作也叫做宏展开:将宏名替换为字符串,即在对相关命令或语句的含义和功能作具体分析之前就要换。

格式:#define 标识符字符串其中标识符就是所谓的符号常量,也称为“宏名”。

例:#define Pi 3.1415926//把程序中出现的Pi全部换成3.1415926 说明:(1)宏名一般用大写;(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。

C语言宏定义

C语言宏定义

C语言宏定义C语言宏定义C语言既具有高级语言的功能,又具有低级语言的许多功能。

那么大家知道C语言宏定义是怎样的呢?下面一起来看看!宏定义是预处理命令的一种,它允许用一个标识符来表示一个字符串。

先看一个例子:#include#define N 100int main(){ int sum = 20 + N; printf("%d ", sum); return 0;}运行结果:120该示例中的语句int sum = 20 + N;,N被100代替了。

#define N 100就是宏定义,N为宏名,100是宏的内容。

在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。

宏定义是由源程序中的宏定义命令#define完成的,宏代换是由预处理程序完成的。

宏定义的一般形式为:#define 宏名字符串#表示这是一条预处理命令,所有的预处理命令都以#开头。

define是预处理命令。

宏名是标识符的一种,命名规则和标识符相同。

字符串可以是常数、表达式等。

这里所说的字符串是一般意义上的字符序列,不要和C语言中的字符串等同,它不需要双引号。

程序中反复使用的表达式就可以使用宏定义,例如:#define M (n*n+3*n)它的作用是指定标识符M来代替表达式(y*y+3*y)。

在编写源程序时,所有的(y*y+3*y)都可由M代替,而对源程序编译时,将先由预处理程序进行宏代换,即用(y*y+3*y)表达式去替换所有的宏名M,然后再进行编译。

将上面的例子补充完整:#include#define M (n*n+3*n)int main(){ int sum, n; printf("Input a number: "); scanf("%d", &n); sum = 3*M+4*M+5*M; printf("sum=%d ", n); return 0;}运行结果:Input a number: 10↙sum=1560上面的程序中首先进行宏定义,定义M来替代表达式(n*n+3*n),在sum=3*M+4*M+5*M中作了宏调用。

define宏定义中的#,##,@#及符号

define宏定义中的#,##,@#及符号

d efine宏定义中的#,##,@#及\符号(ZT)C++ STL学习2011-04-24 18:04:03 阅读19 评论0 字号:大中小订阅1、# (stringizing)字符串化操作符。

其作用是:将宏定义中的传入参数名转换成用一对双引号括起来参数名字符串。

其只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。

如:#define example(instr) printf("the input string is:\t%s\n",#instr)#define example1(instr) #instr当使用该宏定义时:example(abc);在编译时将会展开成:printf("the input string is:\t%s\n","abc");string str=example1(abc);将会展成:string str="abc";注意:对空格的处理a。

忽略传入参数名前面和后面的空格。

如:str=example1( abc );将会被扩展成str="abc";b.当传入参数名间存在空格时,编译器将会自动连接各个子字符串,用每个子字符串中只以一个空格连接,忽略其中多余一个的空格。

如:str=exapme( abc def); 将会被扩展成str="abc def";2、## (token-pasting)符号连接操作符宏定义中:参数名,即为形参,如#define sum(a,b) (a+b);中a和b 均为某一参数的代表符号,即形式参数。

而##的作用则是将宏定义的多个形参成一个实际参数名。

如:#define exampleNum(n) num##nint num9=9;使用:int num=exampleNum(9); 将会扩展成int num=num9;注意:1.当用##连接形参时,##前后的空格可有可无。

C语言中的宏定义

C语言中的宏定义
1. n = MAX(i, MAX(j,k));
下面是预处理后的这条语句:
1. n=((i)>(((j)>(k)?(j):(k)))?(i):(((j)>(k)?(j):(k))));
2) 、宏参数没有类型检查。当一个函数被调用时,编译器会检查每一个参数来确认它们是 否是正确的类型。如果不是,或者将参数转换成正确的类型,或者由编译器产生一个出错信 息。预处理器不会检查宏参数的类型,也不会进行类型转换。 3) 、无法用一个指针来指向一个宏。如在 17.7 节中将看到的,C 语言允许指针指向函数。 这一概念在特定的编程条件下非常有用。 宏会在预处理过程中被删除, 所以不存在类似的 “指 向宏的指针”。因此,宏不能用于处理这些情况。 4) 、宏可能会不止一次地计算它的参数。函数对它的参数只会计算一次,而宏可能会计算 两次甚至更多次。如果参数有副作用,多次计算参数的值可能会产生意外的结果。考虑下面 的例子,其中 MAX 的一个参数有副作用:
1. #define getchar() getc(stdin)
空的参数列表不是一定确实需要, 但可以使 getchar 更像一个函数。 (没错, 这就是<stdio.h> 中的 getchar,getchar 的确就是个宏,不是函数 ——虽然它的功能像个函数。) 使用带参数的宏替代实际的函数的优点: 1) 、 程序可能会稍微快些。一个函数调用在执行时通常会有些额外开销—— 存储上下文 信息、复制参数的值等。而一个宏的调用则没有这些运行开销。 2) 、 宏会更“通用”。与函数的参数不同,宏的参数没有类型。因此,只要预处理后的程序 依然是合法的,宏可以接受任何类型的参数。例如,我们可以使用 MAX 宏从两个数中选出 较大的一个,数的类型可以是 int,long int,float,double 等等。 但是带参数的宏也有一些缺点。

c语言中宏定义中if else语法格式

c语言中宏定义中if else语法格式

C语言中宏定义中if else语法格式1. 宏定义概述在C语言中,宏定义是一种预处理指令,用于将一个标识符替换为一个指定的字符串或代码段。

宏定义可以简化代码,提高代码的可读性和可维护性。

在宏定义中使用if else语法格式,可以根据条件来选择不同的代码段进行替换,从而实现代码的灵活性和通用性。

2. 宏定义中的if else语法格式在C语言中,宏定义中的if else语法格式为:```#define 宏名源代码``````#ifdef 宏名源代码1#else源代码2#endif```3. 宏名的说明宏名是一个标识符,用于在代码中表示一个特定的宏定义。

在定义宏名时,通常使用大写字母和下划线来命名,以区分于普通变量和函数名。

4. ifdef指令#ifdef是一个预处理指令,用于判断指定的宏名是否已经定义。

如果宏名已经定义,则执行源代码1,否则执行源代码2。

5. else指令#ifdef指令的作用是在宏名已经定义的情况下执行源代码1,而else 指令则是在宏名未定义的情况下执行源代码2。

6. endif指令#ifdef和#else之间的源代码1和源代码2是通过#endif指令来结束的。

该指令用于标记#ifdef的结束位置,以便让编译器知道代码的分界。

7. 实例演示下面通过一个实例演示宏定义中的if else语法格式:```#define DEBUG#ifdef DEBUGprintf("Debugging information\n");#elseprintf("No debugging information\n");#endif```在上面的例子中,首先定义了一个名为DEBUG的宏名,然后使用#ifdef指令来判断DEBUG是否已经定义,如果已定义则输出"Debugging information",否则输出"No debugging information"。

define宏定义函数

define宏定义函数

define宏定义函数宏定义是C/C++语言中一种预处理指令,可以用来对代码中的固定值或者复杂表达式进行替换,减少代码编写时的重复性问题,提高代码重用性和可读性。

宏定义的语法格式为:#define 宏名称宏替换文本其中,宏名称是自定义的标识符,宏替换文本可以是单个字符、数值、表达式、函数调用等。

宏定义的有效范围是从定义处到文件末尾或者遇到#undef指令为止。

宏定义的优点在于,它可以让程序员在代码中使用一个短小的名称来代替一个复杂的表达式或者语句,从而提高代码可读性和可维护性。

同时,在编译时,编译器会将所有使用到宏定义的代码中的宏名称展开成对应的宏替换文本,从而使得程序的运行效率得到提高。

宏定义的应用场景非常广泛,例如:1.定义常量:可以使用#define宏定义,将一个固定的值定义为一个常量,方便在代码中多次使用。

例如:#define PI 3.14这样在后续的代码中就可以使用PI来代替3.14,提高可读性和可维护性。

2.定义函数:宏定义可以定义一些简单的函数。

例如:#define max(a,b) ((a)>(b)?(a):(b))这个宏定义表示求取两个数中的最大值,在后续的代码中可以用max(a,b)来代替((a)>(b)?(a):(b)),达到简洁、明了的效果。

3.定义缩写:在代码中,有时需要使用一些比较长的名称来表示一些事物,为了方便使用,可以用宏定义来缩写这些名称,在代码中使用时可以提高可读性和代码规范性。

例如:#define HTTP_STATUS_OK 200#define HTTP_STATUS_BAD_REQUEST 4004.条件编译:宏定义可以用于条件编译,在程序中加入一些特别的代码,根据不同的编译选项选择编译或者不编译这些代码。

例如:#ifdef DEBUGprintf("error message: %s\n", error_msg);#endif如果在编译程序的时候加上了-DDEBUG选项,则会将上述代码编译到程序中,否则会被忽略。

宏定义中##和#的作用

宏定义中##和#的作用
例如:
> #define STRCPY(dst, src) strcpy(dst, #src)

> STRCPY(buff, abc)
相当于strcpy(buff, "abc")
另外,如果##后的参数本身也是一个宏的话,##会阻止这个宏的展开。
#define STRCPY(a, b) s源自rcpy(a ## _p, #b)
__attribute__ ((unused, alias(__stringify(name))))
得到
MODULE_DEVICE_TABLE(usb, products)
/*notes: struct usb_device_id products; */
<==> MODULE_GENERIC_TABLE(usb_device,products)
另外一些分隔标志是,包括操作符,比如+, -, *, /, [,], ...,所以尽管下面的
宏定义没有空格,但是依然表达有意义的定义:define add(a, b) a+b
而其强制连接的作用是,去掉和前面的字符串之间的空格,而把两者连接起来。
2.举列--试比较下述几个宏定义的区别
#define A1(name, type) type name_##type##_type或
<==> extern const struct usb_device_id __mod_usb_device_table
__attribute__ ((unused, alias("products")))
注意到alias attribute需要一个双引号,所以在这里使用了__stringify(name)来

宏定义中使用extern

宏定义中使用extern

宏定义中使⽤extern
全局变量的定义是会得到内存分配且可以被其他模块通过C语⾔中extern关键字调⽤的变量。

所以,必须在 .C 或 .H ⽂件中定义,此种⽅法很容易导致错误。

以下为UCOSIII中定义全局变量的⽅法:
部分源码(Os.h⽂件中):
#ifdef OS_GLOBALS
#define OS_EXT
#else
#define OS_EXT extern
#endif
Os.h⽂件中定义了全局变量OS_EXT;在⽂件"Os_var.c"⽂件中定义了全局变量OS_GLOBALS
源码如下(Os_var.c⽂件中)
#define OS_GLOBALS
当编译器处理"Os_var.C"⽂件时,它使OS_EXT为空,因为OS_GLOBALS已经在"Os_var.c"定义。

所以编译器给每个全局变量分配内存空间,⽽当编译器处理"Os.h"⽂件时,OS_GLOBALS 没有定义,OS_EXT被定义为extern,这样⽤户就可以调⽤外部全局变量。

C语言中宏定义之##用于可变参数

C语言中宏定义之##用于可变参数

C语⾔中宏定义之##⽤于可变参数GCC ⽀持复杂的宏,它使⽤⼀种不同的语法,使你可以给可变参数⼀个名字,如同其它参数⼀样,⽐如:引⽤#define debug(format, args...) fprintf(stderr, format, args)这种定义可读性更强,也更容易描述。

完整测试代码:引⽤#include <stdio.h>#define debug(format, args...) fprintf(stderr, format, args)int main(){char a[20] = "hello world\n";int i = 10;debug("i = %d, %s", i, a);return 0;}运⾏输出:引⽤beyes@linux-beyes:~/C/micro> ./mic.exei = 10, hello world但是上⾯的定义仍存在⼀点问题,如果把上⾯的代码改为下⾯的:引⽤#include <stdio.h>#define debug(format, args...) fprintf(stderr, format, args)int main(){debug("hello world\n");return 0;}那么在编译时会提⽰以下错误:引⽤beyes@linux-beyes:~/C/micro> gcc -g mic.c -o mic.exemic.c: In function ‘main’:mic.c:10: error: expected expression before ‘)’ token提⽰缺少右边括号。

这是因为,当宏展开后,"hello world\n" 代⼊ format,然⽽,在其后还紧跟着⼀个逗号,但是这个逗号后⾯是期望有args 参数的,但这⾥却没有,所以宏不能展开完全,故⽽⽆法编译通过。

单片机中宏定义

单片机中宏定义

单片机中宏定义在单片机编程中,宏定义是指使用预处理指令#define定义的常量、变量、函数等。

宏定义可以在代码中多次使用,提高编写代码的效率。

宏定义的基本语法格式如下:#define 宏名值在定义宏时,宏名和值之间需要用空格隔开。

值可以是数值、字符、字符串等。

例如:#define LED1 1 //定义LED1为1#define SUM(a,b) ((a)+(b)) //定义求和函数SUM(a,b)使用宏时可以直接调用宏名,编译器会自动将宏名替换成所定义的值。

例如:port = LED1; //将端口port设为LED1sum = SUM(10,20); //计算10和20的和,结果为30宏定义在单片机编程中具有重要作用,可以大大提高编程效率和代码的可读性。

一、宏定义的使用1.定义常量在单片机编程中,常量是指值不能被改变的变量,一般使用宏定义来定义常量。

如下面的代码:#define LED1 0x01 //定义LED1为0x01#define LED2 0x02 //定义LED2为0x02#define LED3 0x04 //定义LED3为0x04这样就可以方便地在代码中使用这些常量,例如:P0 = LED1 | LED2; //将P0口的LED1和LED2同时亮起来2.定义函数调用函数时可以使用宏名来代替函数名,例如:LED_ON(); //LED_ON函数被替换成P1 = 0x01;LED_OFF(); //LED_OFF函数被替换成P1 = 0x00;#define MAX 100 //定义MAX为100num = MAX; //将num变量设为MAX的值,即100#define BUF_SIZE 20 //定义BUF_SIZE为20int buf[BUF_SIZE]; //定义buf数组,大小为BUF_SIZEbuf[0] = 0x01; //将buf数组的第一个元素设为0x01二、宏定义的注意事项1.宏名一般要大写为了方便识别和区分,宏名一般使用大写字母来表示,例如:2.宏定义不能被修改一旦定义了宏,不能修改宏定义的值,否则会产生意想不到的后果。

c语言宏定义函数

c语言宏定义函数

c语言宏定义函数
1.什么是C语言宏定义函数
C语言宏定义函数是指在C语言程序中使用宏定义函数实现的一种特殊的代码块,它可以被定义为一组指令的集合。

它的基本结构类似于函数,但它不像函数那样可以调用,而是在编译时处理,在代码执行阶段不存在。

2.宏定义函数的优点
(1)C语言宏定义函数可以简化编码并加快程序执行速度。

(2)C语言宏定义函数改变后,只需编译一次即可实现代码重用,效率较高。

(3)可以使用C语言宏定义函数修改程序的特性,提高程序的可移植性。

3.如何使用宏定义函数
(1)首先,使用#define宏定义函数来定义代码块,然后可以在程序的任何地方使用定义的宏名称来访问代码块,并将代码块复制到表达式中。

(2)其次,可以利用宏定义来实现程序的预处理,例如在编译期间预定义使用的编译器版本和编译程序所在系统平台。

(3)最后,可以利用C语言宏定义函数动态改变程序的行为、运行设置和编译时设置等等。

4.宏定义函数的缺点
(1)宏定义函数会增加程序文件的大小,破坏语言结构,使程序难以理解和维护。

(2)宏定义函数容易产生类似宏替换产生的错误,尤其是当宏定义中的参数可以在运行时发生变化时,很容易导致程序出错。

(3)宏定义函数不支持实参类型检查,会导致程序不具有可移植性。

总之,C语言宏定义函数提供了一种灵活有效的程序实现技术,但也有一定的缺点,在使用时需谨慎,避免出错。

C++ 宏定义说明(详解)

C++ 宏定义说明(详解)

宏定义有无参数宏定义和带参数宏定义两种。

无参数的宏定义的一般形式为# define 标识符字符序列其中# define之后的标识符称为宏定义名(简称宏名),要求宏名与字符序列之间用空格符分隔。

这种宏定义要求编译预处理程序将源程序中随后所有的定名的出现(注释与字符串常量中的除外)均用字符序列替换之。

前面经常使用的定义符号常量是宏定义的最简单应用。

如有: # define TRUE 1# define FALSE 0则在定义它们的源程序文件中,凡定义之后出现的单词TRUE将用1替代之;出现单词FALSE 将用0替代之。

在宏定义的#之前可以有若干个空格、制表符,但不允许有其它字符。

宏定义在源程序中单独另起一行,换行符是宏定义的结束标志。

如果一个宏定义太长,一行不够时,可采用续行的方法。

续行是在键人回车符之前先键入符号"\"。

注意回车要紧接在符号"\"之后,中间不能插入其它符号。

宏定义的有效范围称为宏定义名的辖域,辖域从宏定义的定义结束处开始到其所在的源程序文件末尾。

宏定义名的辖域不受分程序结构的影响。

可以用预处理命令#undef终止宏定义名的辖域。

在新的宏定义中,可以使用前面已定义的宏名。

例如,# define R 2.5# define PI 3.1415926# define Circle 2*PI*R# define Area PI* R * R程序中的Circle被展开为2*3.1415926* 2.5, Area被展开为3.1415926*2.5*2.5。

如有必要,宏名可被重复定义。

被重复定义后,宏名原先的意义被新意义所代替。

通常,无参数的宏定义多用于定义常量。

程序中统一用宏名表示常量值,便于程序前后统一,不易出错,也便于修改,能提高程序的可读性和可移植性。

特别是给数组元素个数一个宏定义,并用宏名定义数组元素个数能部分弥补数组元素个数固定的不足。

注意:预处理程序在处理宏定义时,只作字符序列的替换工作,不作任何语法的检查。

arm中的宏定义

arm中的宏定义

arm中的宏定义
语法格式如下:MACRO [$ label] macroname{ $ parameter1,$ parameter,} 其他指令MEND MACRO 伪操作标识宏定义的开始,MEND 标
识宏定义的结束。

用MACRO 及MEND 定义一段代码,称为宏定义体,这样
在程序中就可以通过宏指令多次调用该代码段。

其中,$ label 在宏指令被展
开时,label 会被替换成相应的符号,通常是一个标号。

宏定义中的$label 是一
个可选参数,在一个符号前使用$表示程序被汇编时将使用相应的值来替代$后
的符号。

macroname 为所定义的宏的名称。

$parameter 为宏指令的参数。

当宏指令被展开时将被替换成相应的值,类似于函数中的形式参数,可以在宏定
义时为参数指定相应的默认值。

例如:
定义宏如下:
MACRO
$label TestBranch$dest, $reg, $cc
$label
CMP $reg,#0
B$cc $dest
MEND
调用宏的过程如下:
testTestBranch Nonzero,r0, NE
Nonzero
............
程序汇编后,宏展开如下:。

c语言宏定义格式

c语言宏定义格式

c语言宏定义格式C语言宏定义格式C语言中的宏定义是一种预处理指令,它可以将一些常用的代码片段定义为一个宏,以便在程序中多次使用。

宏定义的格式如下:#define 宏名替换文本其中,宏名是定义的宏的名称,替换文本是宏定义的内容。

宏名可以是任何合法的标识符,但是不能是C语言的关键字或保留字。

替换文本可以是任何合法的C语言代码,包括表达式、语句、函数等。

宏定义的作用是将一些常用的代码片段定义为一个宏,以便在程序中多次使用。

例如,我们可以定义一个求平方的宏:#define SQUARE(x) ((x)*(x))这个宏定义了一个名为SQUARE的宏,它的替换文本是一个表达式,用来求一个数的平方。

在程序中,我们可以使用这个宏来求任何一个数的平方,例如:int a = 5;int b = SQUARE(a);在这个例子中,宏SQUARE被展开为((a)*(a)),所以b的值为25。

宏定义还可以带参数,例如:#define MAX(x,y) ((x)>(y)?(x):(y))这个宏定义了一个名为MAX的宏,它的替换文本是一个表达式,用来求两个数中的最大值。

在程序中,我们可以使用这个宏来求任何两个数中的最大值,例如:int a = 5;int b = 7;int c = MAX(a,b);在这个例子中,宏MAX被展开为((a)>(b)?(a):(b)),所以c的值为7。

宏定义还可以使用条件编译指令,例如:#ifdef DEBUG#define DEBUG_PRINT(x) printf x#else#define DEBUG_PRINT(x)#endif这个宏定义了一个名为DEBUG_PRINT的宏,它的替换文本是一个printf语句。

在程序中,如果定义了DEBUG宏,则可以使用DEBUG_PRINT来输出调试信息,例如:#define DEBUGDEBUG_PRINT(("a=%d,b=%d\n",a,b));在这个例子中,宏DEBUG_PRINT被展开为printf(("a=%d,b=%d\n",a,b)),所以输出a和b的值。

c 函数宏定义格式

c 函数宏定义格式

c 函数宏定义格式
摘要:
一、函数宏定义概述
二、C语言中函数宏定义的格式
三、函数宏定义的注意事项
四、总结
正文:
一、函数宏定义概述
在C语言编程中,为了提高代码的可维护性和可读性,我们常常需要使用宏定义。

宏定义是一种将常量或代码片段替换为简短标识符的方法。

在C语言中,有两种类型的宏定义:函数宏定义和普通宏定义。

函数宏定义主要用于将一个函数替换为一个宏,从而简化调用该函数的方式。

二、C语言中函数宏定义的格式
在C语言中,函数宏定义的格式如下:
```c
#define 宏名(参数列表) 函数体
```
其中,`宏名` 是用于调用宏的标识符,`参数列表` 是传递给宏的参数,`函数体` 是宏要执行的代码。

在函数体中,我们可以使用`#`指令来引用参数列表中的参数。

例如,我们可以定义一个计算两个数之和的函数宏:
```c
#define ADD(a, b) ((a) + (b))
```
使用这个宏时,只需像调用普通函数一样调用它:
```c
int sum = ADD(3, 4); // 结果为7
```
三、函数宏定义的注意事项
1.宏名和参数列表之间不能有空格。

2.函数宏定义中的参数列表必须用括号括起来。

3.函数宏定义中的参数在宏体中可用`#`指令引用,例如`#1`、`#2`等。

4.函数宏定义不能嵌套定义。

5.函数宏定义中的参数可以是常量、变量或表达式,但不能是函数调用。

四、总结
C语言中的函数宏定义是一种将函数简化为宏的方法,可以提高代码的可读性和可维护性。

C++ 宏定义中字符串连接操作详解

C++ 宏定义中字符串连接操作详解

关于记号粘贴操作符(token paste operator): ##1. 简单的说,“##”是一种分隔连接方式,它的作用是先分隔,然后进行强制连接。

其中,分隔的作用类似于空格。

我们知道在普通的宏定义中,预处理器一般把空格解释成分段标志,对于每一段和前面比较,相同的就被替换。

但是这样做的结果是,被替换段之间存在一些空格。

如果我们不希望出现这些空格,就可以通过添加一些##来替代空格。

另外一些分隔标志是,包括操作符,比如 +, -, *, /, [,], …,所以尽管下面的宏定义没有空格,但是依然表达有意义的定义: define add(a, b) a+b而其强制连接的作用是,去掉和前面的字符串之间的空格,而把两者连接起来。

2. 举列–试比较下述几个宏定义的区别#define A1(name, type) type name_##type##_type 或#define A2(name, type) type name##_##type##_typeA1(a1, int); /* 等价于: int name_int_type; */A2(a1, int); /* 等价于: int a1_int_type; */解释:1) 在第一个宏定义中,”name”和第一个”_”之间,以及第2个”_”和第二个”type”之间没有被分隔,所以预处理器会把name_##type##_type解释成3段:“name_”、“type”、以及“_type”,这中间只有“type”是在宏前面出现过的,所以它可以被宏替换。

2) 而在第二个宏定义中,“name”和第一个“_”之间也被分隔了,所以预处理器会把name##_##type##_type解释成4段:“name”、“_”、“type”以及“_type”,这其间,就有两个可以被宏替换了。

3) A1和A2的定义也可以如下:#define A1(name, type) type name_ ##type ##_type<##前面随意加上一些空格>#define A2(name, type) type name ##_ ##type ##_type 结果是## 会把前面的空格去掉完成强连接,得到和上面结果相同的宏定义3. 其他相关–单独的一个 #至于单独一个#,则表示对这个变量替换后,再加双引号引起来。

c语言 宏定义函数

c语言 宏定义函数

C语言宏定义函数1. 什么是宏定义函数?在C语言中,宏定义函数是一种预处理器指令,用来在编译阶段对代码进行替换。

宏定义函数可以将一段代码或表达式定义为一个标识符,便于在程序中多次使用。

宏定义函数的语法形式如下:#define 标识符替换文本其中,标识符是由字母、数字和下划线组成的标识符,替换文本是一段代码或表达式。

当程序中出现标识符时,预处理器会将其替换为对应的替换文本。

2. 宏定义函数的优点宏定义函数在C语言中有许多优点,包括:2.1 提高代码的可读性通过宏定义函数,可以将一段复杂的代码替换为一个简洁的标识符,使代码更易读、易懂。

例如,可以将一些常用的计算操作定义为宏,如计算平方、判断奇偶等。

2.2 提高代码的复用性通过宏定义函数,可以将一段代码定义为一个宏,在程序的任何地方都可以使用。

这样可以避免重复编写相同的代码,提高代码的复用性。

2.3 减少代码量宏定义函数可以将一段代码替换为一个宏,从而减少代码的长度。

这不仅可以提高代码的可读性,还可以减少编码工作量。

2.4 提高程序的执行效率由于宏定义函数是在编译阶段进行代码替换的,相比于函数调用,宏定义函数的执行效率更高。

不需要函数调用的开销,可以提高程序的执行效率。

3. 宏定义函数的注意事项在使用宏定义函数时,需要注意以下几点:3.1 代码替换规则宏定义函数是在编译阶段进行代码替换的,因此需要特别注意替换的规则。

在定义宏时,可以使用参数列表来实现变量替换,但需要注意参数的类型和替换的位置。

3.2 替换文本的括号问题在定义宏时,需要注意替换文本中的括号问题。

特别是在宏定义函数中使用括号时,需要使用额外的括号来保证代码的正确性。

否则,可能会导致替换后的代码逻辑错误。

3.3 宏定义函数的作用域宏定义函数的作用域是全局的,在程序的任何地方都可以使用。

这样可能会导致命名冲突的问题,因此需要对宏定义函数的命名进行规范,避免与其他代码产生冲突。

3.4 可读性和维护性问题宏定义函数可以提高代码的可读性,但如果过度使用宏定义函数,可能会导致代码变得难以理解和维护。

宏定义(无参宏定义和带参宏定义),C语言宏定义详解

宏定义(无参宏定义和带参宏定义),C语言宏定义详解

宏定义(⽆参宏定义和带参宏定义),C 语⾔宏定义详解1、宏定义说明宏定义是⽐较常⽤的预处理指令,即使⽤“标识符”来表⽰“替换列表”中的内容。

标识符称为宏名,在预处理过程中,预处理器会把源程序中所有宏名,替换成宏定义中替换列表中的内容。

常见的宏定义有两种,不带参数的宏定义和带参数的宏定义。

2、⽆参宏定义⽆参数宏定义的格式为:#define 标识符替换列表替换列表可以是数值常量、字符常量、字符串常量等,故可以把宏定义理解为使⽤标识符表⽰⼀常量,或称符号常量。

说明:1. 可以不在⾏⾸,但只允许它前⾯有空格符。

例如:#define PI 3.1416 //正确,该⾏#前允许有空格int a;#define N 5 //错误,该⾏#前不允许有空格外的其他字符2. 标识符和替换列表之间不能加赋值号 =,替换列表后不能加分号#define N =5 //虽语法正确,但预处理器会把N替换成=5int a[N]; //错误,因为宏替换之后为 int a[=5];宏定义不是语句,是预处理指令,故结尾不加分号。

如果不⼩⼼添加了分号,虽然有时该宏定义没问题,但在宏替换时,可能导致 C 语法错误,或得不到预期结果。

例如:#define N 5; //虽语法正确,但会把N替换成5;int a[N]; //语法错误,宏替换后,为int a[5;];错误3. 由于宏定义仅是做简单的⽂本替换,故替换列表中如有表达式,必须把该表达式⽤括号括起来,否则可能会出现逻辑上的“错误”。

例如:#define N 3+2int r = N * N;宏替换后为:int r=3+2*3+2; //r=11如果采⽤如下形式的宏定义:#define N (3+2)int r=N*N;则宏替换后,为:int r=(3+2)*(3+2); //r=254. 当替换列表⼀⾏写不下时,可以使⽤反斜线\作为续⾏符延续到下⼀⾏。

例如:#define USA "The United \States of \America"该宏定义中替换列表为字符串常量,如果该串较长,或为了使替换列表的结构更清晰,可使⽤续⾏符 \ 把该串分若⼲⾏来写,除最后⼀⾏外,每⾏⾏尾都必须加续⾏符 \。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C语言宏定义中"#","#@"和"##"的用法一、引言#define macro(a)#a#define macro2(a,b)a##b#define macro3(a,b,c)a##b##c#a,表示a不再是一个变量,而变成了字符串"a"##表示连接,a##b,表示输入的参数名为ab,a##b##c同理,代表变量名为:abc测试例子:int x=3;int y=4;int xy=10;int xyz=20;CString str;OutputDebugString(macro(x));str.Format("%d",macro2(x,y));OutputDebugString(str);str.Format("%d",macro3(x,y,z));OutputDebugString(str);输出结果为:x1020第一个为x,marco(x),x变成了"x"字符串第二个为10,macro(x,y),就是变量xy第三个为20,macro(x,y,z),就是变量xyz二、一般用法#把宏参数变为一个字符串,#@把宏参数变为一个字符,##把两个宏参数贴合在一起。

#include<stdio.h>#include<limits.h>#define STR(s)#s//#与参数之间可以有空格#define TOCHAR(c)#@c#define CONS(a,b)int(a##e##b)//##与参数之间可以有空格int main(void){printf(STR(pele));//输出字符串"pele"printf("%c\n",TOCHAR(z));//输出字符zprintf("%d\n",CONS(2,3));//2e3输出:2000return0;}三、当宏参数是另一个宏的时候需要注意的是凡宏定义里有用'#'或'##'的地方宏参数是不会再展开的。

#define A(2)#define STR(s)#s#define CONS(a,b)int(a##e##b)printf("int max:%s\n",STR(INT_MAX));这行会被展开为:printf("int max:%s\n","INT_MAX");printf("%s\n",CONS(A,A));这一行被展开为:printf("%s\n",int(AeA));INT_MAX和A都不会再被展开,然而解决这个问题的方法很简单,多加一层中间转换宏。

加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数。

#define A(2)#define_STR(s)#s#define STR(s)_STR(s)//转换宏#define_CONS(a,b)int(a##e##b)#define CONS(a,b)_CONS(a,b)//转换宏printf("int max:%s\n",STR(INT_MAX));输出为:int max:0x7fffffffSTR(INT_MAX)-->_STR(0x7fffffff)-->"0x7fffffff"printf("%d\n",CONS(A,A));输出为:200CONS(A,A)-->_CONS((2),(2))-->int((2)e(2))以下为Minix3操作系统相关的源代码:#ifdef_ANSI#define__str(x)#x#define__xstr(x)__str(x)//转换宏_PROTOTYPE(void__bad_assertion,(const char*_mess));#define assert(expr)((expr)?(void)0:\__bad_assertion("Assertion\""#expr\"\"failed,file"__xstr(__FILE__)\",line"__xstr(__LINE__)"\n"))四、"#"和"##"的一些应用特例1、合并匿名变量名#define___ANONYMOUS1(type,var,line)type var##line#define__ANONYMOUS0(type,line)___ANONYMOUS1(type,_anonymous,line) #define ANONYMOUS(type)__ANONYMOUS0(type,__LINE__)例:ANONYMOUS(static int);即:static int_anonymous70;70表示该行行号;第一层:ANONYMOUS(static int);-->__ANONYMOUS0(static int,__LINE__);第二层:-->___ANONYMOUS1(static int,_anonymous,70);第三层:-->static int_anonymous70;即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;2、填充结构#define FILL(a){a,#a}enum IDD{OPEN,CLOSE};typedef struct MSG{IDD id;const char*msg;}MSG;MSG_msg[]={FILL(OPEN),FILL(CLOSE)};相当于:MSG_msg[]={{OPEN,"OPEN"},{CLOSE,"CLOSE"}};3、记录文件名#define_GET_FILE_NAME(f)#f#define GET_FILE_NAME(f)_GET_FILE_NAME(f)//转换宏static char FILE_NAME[]=GET_FILE_NAME(__FILE__);4、得到一个数值类型所对应的字符串缓冲大小#define_TYPE_BUF_SIZE(type)sizeof#type#define TYPE_BUF_SIZE(type)_TYPE_BUF_SIZE(type)char buf[TYPE_BUF_SIZE(INT_MAX)];-->char buf[_TYPE_BUF_SIZE(0x7fffffff)];-->char buf[sizeof"0x7fffffff"];这里相当于:char buf[11];五、C/C++宏定义的可变参数编写代码的过程中,经常会输出一些调试信息到屏幕上,一般会调用printf这类的函数。

但是当调试解决之后,我们需要手工将这些地方删除或者注释掉。

再这次的项目中就用到类似问题,为了调试程序,再一些地方输出了很多的信息,随着项目的调试,输出的信息越来越多。

于是就面临着,如何处理这些输出信息的语句。

简单删掉,不仅有一定的工作量,而且也不能保证之后就不出现问题,出现问题后这些信息还是有用的。

不去掉,带着调试信息就上线,这是明显不允许的。

于是就想到了一个可行的办法。

如下:void myprintf(char*fmt,...){}#ifdef DEBUG#define printf(fmt,args...)myprintf(fmt,##args)#endif调试阶段带着DEBUG调试,正式上线就可以把printf变成一个空函数了。

这样做的一个潜在风险是可能会导致默写glib函数需要调用printf输出错误log也给取消掉了。

令人欣慰的是,大部分glib调用的应该是fprintf。

虽然问题解决了,但是我对args...以及##args还是不太了解。

上网找了些gcc手册的资料如下:带有可变参数的宏(Macros with a Variable Number of Arguments)在1999年版本的ISO C标准中,宏可以象函数一样,定义时可以带有可变参数。

宏的语法和函数的语法类似。

下面有个例子:#define debug(format,...)fprintf(stderr,format,__VA_ARGS__)这里,‘…’指可变参数。

这类宏在被调用时,它(这里指‘…’)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。

当被调用时,在宏体(macro body)中,那些符号序列集合将代替里面的__VA_ARGS__标识符。

更多的信息可以参考CPP手册。

GCC始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。

例如下面的例子:#define debug(format,args...)fprintf(stderr,format,args)这和上面举的那个ISO C定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。

GNU CPP还有两种更复杂的宏扩展,支持上面两种格式的定义格式。

在标准C里,你不能省略可变参数,但是你却可以给它传递一个空的参数。

例如,下面的宏调用在ISO C里是非法的,因为字符串后面没有逗号:debug("A message")GNU CPP在这种情况下可以让你完全的忽略可变参数。

在上面的例子中,编译器仍然会有问题(complain),因为宏展开后,里面的字符串后面会有个多余的逗号。

为了解决这个问题,CPP使用一个特殊的‘##’操作。

书写格式为:#define debug(format,...)fprintf(stderr,format,##__VA_ARGS__)这里,如果可变参数被忽略或为空,‘##’操作将使预处理器(preprocessor)去除掉它前面的那个逗号。

如果你在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,它会把这些可变参数放到逗号的后面。

象其它的pasted macro参数一样,这些参数不是宏的扩展。

参考资料:[1]/s/blog_550405a10100bqar.html[2]Minix操作系统内核代码。

相关文档
最新文档