cc++宏的使用总结
c语言宏的用法
c语言宏的用法C语言程序中广泛的使用宏定义,采用关键字define进行定义,宏只是一种简单的字符串替换,根据是否带参数分为无参和带参。
宏的简单应用很容易掌握,下面小编就跟大家分享下c语言宏的用法。
c语言宏的用法如下:1.宏的基本构成(1)宏中包含特殊符号:#、##.(2)宏定义用do{ }while(0)2、特殊符号#、##(1)#Whenyouputa#beforeanargumentinapreprocessor macro,thepreprocessorturnsthatargumentintoacharacterarray.在一个宏中的参数前面使用一个#,预处理器会把这个参数转换为一个字符数组简化理解:#是“字符串化”的意思,出现在宏定义中的#是把跟在后面的参数转换成一个字符串#define ERROR_LOG(module) fprintf(stderr,"error: "#module"\n")ERROR_LOG("add"); 转换为 fprintf(stderr,"error: "add"\n");ERROR_LOG(devied =0); 转换为fprintf(stderr,"error: devied=0\n");(2)##“##”是一种分隔连接方式,它的作用是先分隔,然后进行强制连接。
在普通的宏定义中,预处理器一般把空格解释成分段标志,对于每一段和前面比较,相同的就被替换。
但是这样做的结果是,被替换段之间存在一些空格。
如果我们不希望出现这些空格,就可以通过添加一些##来替代空格。
1 #define TYPE1(type,name) type name_##type##_type2 #define TYPE2(type,name) type name##_##type##_typeTYPE1(int, c);转换为:int name_int_type ; (因为##号将后面分为 name_ 、type 、 _type三组,替换后强制连接)TYPE2(int, d);转换为:int d_int_type ;(因为##号将后面分为name、_、type 、_type四组,替换后强制连接)3、宏定义中do{ }while(0)第一眼看到这样的宏时,觉得非常奇怪,为什么要用do……while(0)把宏定义的多条语句括起来?非常想知道这样定义宏的好处是什么,于是google、百度一下了。
C语言中如何使用宏
C语言中如何使用宏C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念)。
下面对常遇到的宏的使用问题做了简单总结。
宏使用中的常见的基础问题#符号和##符号的使用...符号的使用宏的解释方法我们能碰到的宏的使用宏使用中的陷阱常见的基础性问题关于#和##在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。
比如下面代码中的宏:#define WARN_IF(EXP) \do{ if (EXP) \fprintf(stderr, "Warning: " #EXP "\n"); } \while(0)那么实际使用中会出现下面所示的替换过程:WARN_IF (divider == 0);被替换为do {if (divider == 0)fprintf(stderr, "Warning" "divider == 0" "\n");} while(0);这样每次divider(除数)为0的时候便会在标准错误流上输出一个提示信息。
而##被称为连接符(concatenator),用来将两个Token连接为一个Token。
注意这里连接的对象是Token就行,而不一定是宏的变量。
比如你要做一个菜单项命令名和函数指针组成的结构体的数组,并且希望在函数名和菜单项命令名之间有直观的、名字上的关系。
那么下面的代码就非常实用:struct command{char * name;void (*function) (void);};#define COMMAND(NAME) { NAME, NAME ## _command }// 然后你就用一些预先定义好的命令来方便的初始化一个command结构的数组了:struct command commands[] = {COMMAND(quit),COMMAND(help),...}COMMAND宏在这里充当一个代码生成器的作用,这样可以在一定程度上减少代码密度,间接地也可以减少不留心所造成的错误。
宏的使用实验报告
一、实验目的1. 理解宏的概念及其作用。
2. 掌握宏的创建和使用方法。
3. 体会宏在提高工作效率方面的优势。
二、实验环境1. 操作系统:Windows 102. 编程语言:Python3.83. 编辑器:PyCharm三、实验内容1. 宏的概念及作用2. 宏的创建3. 宏的使用4. 宏的优势四、实验步骤1. 宏的概念及作用宏是一种编程技巧,可以将多个命令组合成一个单独的命令,从而简化操作过程。
在Python编程中,宏可以帮助我们快速执行重复性的任务,提高工作效率。
2. 宏的创建(1)打开Python编程环境,创建一个新的Python文件。
(2)在文件中输入以下代码:```pythondef my_macro():print("Hello, World!")print("This is a macro.")```(3)将上述代码保存为“macro.py”。
3. 宏的使用(1)在PyCharm或其他Python编程环境中,打开“macro.py”文件。
(2)在代码编辑区,找到“my_macro”函数定义。
(3)将鼠标悬停在“my_macro”函数定义上,按住鼠标左键并拖动到代码编辑区的空白区域。
(4)松开鼠标左键,此时会在空白区域生成一个名为“my_macro”的宏。
(5)在代码编辑区,将光标定位到需要使用宏的位置。
(6)将鼠标悬停在宏上,按住鼠标左键并拖动到光标所在位置。
(7)松开鼠标左键,此时“my_macro”函数将被插入到光标所在位置。
4. 宏的优势(1)提高工作效率:通过宏,可以将多个命令组合成一个单独的命令,简化操作过程,从而提高工作效率。
(2)代码复用:宏可以将重复性的任务封装起来,方便在其他地方复用。
(3)易于维护:当需要修改宏中的代码时,只需修改宏的定义,而不必在多个地方进行修改。
五、实验总结通过本次实验,我们了解了宏的概念及其作用,掌握了宏的创建和使用方法,并体会到了宏在提高工作效率方面的优势。
c语言宏的用法
c语言宏的用法C语言中的宏(macro)是一种预处理指令,用于在编译过程中对程序进行简单的文本替换。
宏定义的格式一般为`#define`,后跟宏的名称和替换的文本。
宏的使用可以简化代码书写、提高代码的可读性和可维护性。
宏的使用可以提高代码的可读性,减少重复的代码。
例如,可以定义一个用于交换两个变量的宏`#define SWAP(a, b) {int tmp; tmp=a; a=b; b=tmp;}`,使用时只需写`SWAP(某, y)`,宏会被替换为实际的交换代码。
这样可以避免多次编写相同的交换代码。
宏还可以帮助实现条件编译,根据条件在编译时选择是否包含某段代码。
例如,可以定义一个用于调试输出的宏:```#ifdef DEBUG#define PRINT_DEBUG(msg) printf("Debug: %s\n", msg)#else#define PRINT_DEBUG(msg)#endif```当定义了`DEBUG`宏时,可以使用`PRINT_DEBUG("message")`输出调试信息;否则,调试输出语句会被为空替换。
通过宏的条件编译,可以方便地在调试和发布版本之间切换。
宏的使用也需注意一些潜在的问题。
首先,宏的替换是简单的文本替换,可能会导致意外的结果。
例如,定义一个用于计算立方的宏`#define CUBE(某) 某某某某某`,使用时`y = CUBE(2 + 3)`会被替换为`y =2 +3 某 2 + 3 某 2 + 3`,导致错误的计算结果。
这种问题可以通过使用括号来解决,即`#define CUBE(某) ((某) 某 (某) 某 (某))`。
其次,宏的使用会增加代码的长度和复杂度,可能会降低代码的可读性和可维护性。
宏替换发生在编译阶段,生成的代码可能难以阅读和调试。
为了避免宏的使用被滥用,可以合理使用宏,避免定义过长或过于复杂的宏。
C语言宏的使用方法和注意事项
C语言宏的使用方法和注意事项C语言宏是一种在程序中定义的预处理指令,它可以将一段代码片段替换为另一段代码片段,从而实现代码的复用和简化。
宏的使用方法和注意事项对于C语言程序员来说非常重要,下面将介绍一些常见的使用方法和需要注意的问题。
一、宏的基本语法和使用方法在C语言中,使用宏需要使用宏定义指令`#define`。
宏定义的基本语法如下:```#define 宏名替换文本```宏名是用户自定义的标识符,替换文本是要替换的代码片段。
宏定义通常放在程序的开头或者头文件中。
宏的使用方法非常简单,只需要在代码中使用宏名即可。
在编译时,预处理器会将宏名替换为对应的代码片段。
例如:```#define PI 3.1415926float r = 5.0;float area = PI * r * r;```在上面的代码中,宏定义了一个常量PI,它的值为3.1415926。
在计算圆的面积时,直接使用了宏PI,而不需要写出具体的数值。
二、宏的参数和参数化宏宏不仅可以替换代码片段,还可以接受参数。
定义带参数的宏需要在宏名后面加上参数列表,参数列表使用圆括号括起来。
例如:```#define MAX(a, b) ((a) > (b) ? (a) : (b))int max = MAX(10, 20);```在上面的代码中,宏定义了一个带两个参数的宏MAX,它返回两个参数中的较大值。
在使用宏时,直接传入具体的数值,宏会自动进行参数替换和计算。
参数化宏的使用可以大大提高代码的灵活性和复用性。
通过定义不同的参数,可以轻松实现不同的功能。
但是需要注意,宏的参数是没有类型的,它只是简单的文本替换,所以在使用宏时需要注意参数的类型和表达式的正确性。
三、宏的注意事项在使用宏时,需要注意以下几个问题:1. 宏的替换文本不要使用分号。
因为宏的替换是简单的文本替换,如果在替换文本中加上分号,会导致使用宏的地方出现多余的分号,从而引发编译错误。
宏编辑器使用技巧详解
宏编辑器使用技巧详解宏编辑器是一种功能强大的工具,可以自动化执行一系列的操作。
以下是宏编辑器的使用技巧,让您更加高效地使用它。
首先,了解宏的基本概念。
宏是由一系列操作组成的脚本,可以自动执行这些操作。
在宏编辑器中,您可以录制宏、编辑宏和运行宏。
录制宏是最常用的功能之一。
录制宏可以将您在软件中执行的操作记录下来,并生成相应的宏脚本。
在录制过程中,您可以按下快捷键启动和停止录制,或者使用菜单选项。
录制宏时,要注意执行操作的顺序和准确性。
编辑宏是进一步优化和定制宏的过程。
编辑宏可以删除、编辑或添加操作,以适应特定的需求。
您可以更改操作的参数和顺序,也可以添加条件语句和循环控制语句。
编辑宏时,要确保它的逻辑正确和有效。
在运行宏之前,您可以选择设置宏的触发方式。
宏可以根据特定的触发条件自动执行,也可以手动启动。
您可以将宏设置为在特定的事件发生时自动运行,也可以设置快捷键来启动和停止宏。
选择合适的触发方式,可以提高宏的使用效率。
另外,了解宏编辑器的快捷键也是很重要的。
宏编辑器通常有一些常用操作的快捷键,例如录制、停止录制、运行和编辑宏。
熟悉这些快捷键,可以节省您的时间和精力。
最后,要学会使用宏编辑器的调试功能。
宏可能会出现错误或不正确的操作,因此调试是非常重要的。
您可以使用单步执行功能,逐步检查宏的执行过程。
在调试时,可以查看每个操作的执行结果,并进行必要的修改和调整。
总结起来,宏编辑器是一个非常强大且实用的工具,可以帮助我们自动化执行一系列的操作。
通过了解宏的基本概念,录制、编辑和运行宏,设置触发方式,熟悉快捷键和调试功能,我们可以更加高效地使用它。
希望以上的宏编辑器使用技巧能为您带来帮助。
c中宏的使用
在C语言中使用宏,我们经常这么做,但是为什么使用宏,他可以做什么,我们或许只是一知半解,下面简单介绍如何在C语言中使用宏预处理器。
#define语句对于define语句,我们已经非常熟悉,一个宏定义语句,主要用途是定义符号常量,如:#define PI 3.14159定义了圆周率PI 为3.14159,在以后用到3.14159的地方直接用PI代替即可,也方便我们编写代码,更大的好处是,如果我不想将圆周率定为3.14159而要求更高精度,如3.14159265,则只需将上面的宏定义改为:#define PI 3.1415926即可,无需到程序中用到这个值的地方逐一修改。
下面介绍#define的高级应用A、带有参数的宏定义语句我们也可以定义接受参数的符号,如AQUARE:#define SQUARE(x) x*x在以后用到SQUARE(a) 是,将会自动用a*a替换,如SQUARE(3)将被替换成3*3,这个函数的好处是不论x是什么类型,都可进行同样的处理,double,int类型都可处理,但存在一个问题,如y=SQUARE(a+1)则将被替换成a+1*a+1这不是我们想要的结果,所以最好用下面的方法定义[size=+0]#define SQUARE(x) (x)*(x)类似可以定义如下函数:[size=+0]#define MAX(a,b) ((a)>(b))?(a):(b))B、接受可变参数个数的宏宏定义同样可以接受可变参数个数的参数列表,为了向预处理器表明我们的宏接受可变参数,可以在参数列表后面跟上三个点(...),在随后的宏定义表达式中,我们使用特殊符号__V A_ARGS__来代表具体参数(注意,前后是双下划线),例如我们定义:#define debugPrintf(...) printf("DEBUG: "__V A_ARGS__)则可用下面方式使用该宏debugPrintf("Hello world\n");或者debugPrintf("i= %d, j=%d \n",i,j);输出分别为(加入i=100,j=200):DEBUG: Hello WorldDEBUG: i=100, j=200C、#操作符如果我们在参数操作符的前面放置一个#,那么C语言的预处理器将使用该参数生成一个常数字符串,例如我们定义str如下:#define str(x) #x如果在程序中输入语句str(testing)最终展开形式将会是"testing"而语句printf(str(Programming in C is fun:\n));将被转换为:printf("Programming in C is fun:\n");D、##操作符在宏定义中,这个操作符可以把两个符号连接起来。
如何使用宏记录和运行
如何使用宏记录和运行宏是一种强大的工具,它可以帮助你自动执行一系列操作,提高工作效率。
在日常工作中,我们经常需要执行一些重复的任务或者输入一些固定的内容,这时候,使用宏就可以很好地解决这些问题。
本文将介绍如何使用宏来记录和运行,以及一些使用宏的技巧和注意事项。
一、宏的概念和基本用法在软件或者办公工具中,宏指的是一系列的指令或者操作的集合。
宏可以记录你的操作,并且可以按照你预先定义的指令来运行这些操作。
通过使用宏,你可以自动化日常工作中一些重复的任务,提高工作效率。
使用宏的基本步骤如下:1. 记录宏:在需要执行的操作前,开始录制一个宏。
录制宏的方法因软件而异,通常可以在软件的菜单栏中找到“录制宏”的功能。
2. 执行操作:按照需要执行的操作顺序进行操作,宏会记录下你的每一步操作,包括鼠标点击、键盘输入等。
3. 停止录制:在完成操作后,停止宏的录制,保存录制的宏。
4. 运行宏:当需要执行这些操作时,只需要运行保存的宏,宏会自动按照你之前录制的操作顺序执行。
二、宏的高级用法除了基本的宏录制和运行,还有一些宏的高级用法可以帮助我们更好地利用宏。
1. 参数化宏:有时候,我们需要根据不同的情况来执行一系列操作。
参数化宏可以在运行宏时传递参数,根据参数不同执行不同的操作。
这样可以实现更加灵活的宏功能。
2. 宏的编辑和修改:保存的宏可以随时编辑和修改,你可以根据实际需要对宏进行修改和优化。
3. 宏的快捷键设置:在一些软件中,你可以为宏设置快捷键。
这样,在你按下快捷键时,宏就会自动运行,方便快捷。
三、宏的使用技巧和注意事项在使用宏时,有一些技巧和注意事项可以帮助我们更好地利用宏,提高工作效率。
1. 合理安排宏的执行顺序:在录制宏时,要确保宏的执行顺序是正确的,不会因为操作的先后顺序不对而导致宏执行出错。
2. 验证宏的正确性:在保存宏后,最好进行一次验证,确保宏可以正常运行并且达到预期的效果。
3. 不要过度依赖宏:宏虽然可以提高工作效率,但并不是解决所有问题的万能工具。
c语言 宏高级用法
c语言宏高级用法宏是C语言中一种强大的工具,可以在编译阶段对代码进行替换和扩展。
除了常见的宏定义,C语言还有一些高级用法可以进一步提升宏在程序中的灵活性和效率。
首先,C语言中的宏可以接受变长参数,使得宏的调用更加灵活。
通过在宏定义中使用省略号(...)表示可变参数,我们可以在宏内对可变参数进行处理。
例如,可以定义一个可变参数的宏来实现类似printf函数的功能:```#define PRINTF(format, ...) printf(format, __VA_ARGS__)```这样,我们就可以使用宏来输出格式化的信息:```PRINTF("Hello, %s! Today is %d-%d-%d.", name, year, month, day);```其次,宏还可以使用条件编译来实现在不同情况下的不同行为。
通过在宏定义中使用#if、#elif、#else和#endif预处理指令,可以在编译时根据条件选择性地定义宏。
这在一些需要根据不同平台或编译选项进行不同处理的场景中非常有用。
例如:```#if defined(WIN32)#define PLATFORM_NAME "Windows"#elif defined(LINUX)#define PLATFORM_NAME "Linux"#else#define PLATFORM_NAME "Unknown"#endif```最后,C语言的宏还可以帮助我们编写通用且高效的代码。
通过宏的替换规则,我们可以在编译阶段对代码进行优化。
例如,可以使用宏来定义简单的位操作:```#define SET_BIT(var, bit) ((var) |= (1 << (bit)))#define CLEAR_BIT(var, bit) ((var) &= ~(1 << (bit)))```这样,我们就可以使用宏以更简洁的方式进行位操作:```SET_BIT(flags, 3);CLEAR_BIT(flags, 7);```总之,C语言中宏的高级用法可以提供更多灵活性和效率。
c语言常用宏定义的用法介绍
c语言常用宏定义的用法介绍宏是C语言中常用的编译预处理功能之一。
在编程时,可以使用宏来代替一些常量或表达式,给程序员提供了便利,使程序更加清晰,便于阅读和理解,进一步提高了程序的运行效率。
另外,在C语言中,宏是产生内嵌代码的唯一方法,并且可以定义带参数的宏,对于嵌入式系统而言,为了能达到性能要求,宏是一种很好的代替函数的方法。
但是如果对宏命令本质理解不透彻,在使用时可能运行的结果与预期的结果就会大相径庭。
下面具体介绍C语言中宏的使用(即宏定义、宏调用、宏展开)。
在C语言源程序中,允许用一个标识符表示一个字符串,称为“宏”;被定义为宏的标识符称为“宏名”。
宏定义是由源程序中的宏定义命令完成的。
该命令有两种形式:一种是无参数的宏定义;另外一种是带参数的宏定义。
(一)无参数的宏定义无参数宏的宏名后不带参数。
其定义的一般形式为:#define标识符字符串#是预处理命令的标志,define是宏定义命令的标志。
标识符为宏名,字符串可以是常量、表达式、格式串等。
例如:#definePI3.1415926#defineSUM(1+2)(二)带参数的宏定义带参数的宏定义,也称为宏函数,在宏定义中的参数称为形式参数,形式参数不分配内存单元,所以不必作类型定义。
带参数的宏定义的一般— 1 —形式如下:#define宏名(参数表)宏体例如:#defineAREAR(R)3.14*R*R#defineSUM(X,Y)X+Y两种格式的宏定义必须写在函数的外边,其作用域为宏定义命令起到源程序结束,若要终止其作用域可以用#undef命令加宏名,宏定义也允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。
(一)宏展开及调用的概念编译预处理时程序中出现的所有宏名都要有宏定义中的字符串来代换,称为宏展开。
嵌套的宏定义,展开时要层层展开。
程序中字符串内的字符跟宏名相同时作为一般字符处理,不用宏展开。
对于带参数的宏的使用称为宏调用,一般形式为:宏名(实参表);在调用中,不仅要宏展开,而且要用实参去代换形参。
c语言宏详解 -回复
c语言宏详解-回复C语言宏详解在C语言中,宏是一种强大的编程工具。
宏是在编译预处理阶段展开的一段代码,它可以被用来定义常量、函数和复杂的代码块。
本文将详细介绍C语言宏的概念、优点和使用方法,并给出一些实际应用案例。
一、宏的概念宏是C语言的一种预处理指令,用来在编译预处理阶段对代码进行处理。
它的基本语法格式为:#define NAME value。
其中,NAME表示宏的名称,value表示宏的值。
当编译器在后续代码中遇到宏名称时,会将其替换为对应的值或代码片段。
宏也可以带有参数,使用时需要在参数前加上“#”符号。
例如,#define MAX(a, b) ((a) > (b) ? (a) : (b))就可以定义一个宏函数,用来返回两个数中的较大值。
在使用时,可以通过MAX(x, y)来获得x和y中的最大值。
宏中的参数可以是任意合法的C表达式。
宏是一个简单而强大的工具,它可以提高代码的简洁性和可读性。
通过宏的定义,我们可以将一些常用的表达式或操作封装为一个宏,从而使代码更加简洁明了。
二、宏的优点1. 提高代码的简洁性和可读性。
通过宏的定义,我们可以用一个简单的名称来代替一段冗长的代码。
这不仅使代码更加简洁,而且使代码更易于阅读和理解。
2. 提高代码的可维护性。
宏可以将一些重复的代码片段抽象为一个宏,方便后续的维护和修改。
如果需要修改这段代码,只需要修改宏的定义,而不需要修改所有的调用点。
3. 提高代码的复用性。
宏可以被多次调用,从而实现代码的复用。
只需要在需要使用的地方调用宏即可,无需重复编写相同的代码。
三、宏的使用方法1. 定义常量。
我们可以使用宏来定义一些常量,以便在后续的代码中使用。
例如,#define PI 3.14159可以定义一个名为PI的常量,表示圆周率。
2. 定义简单函数。
宏可以用来定义一些简单的函数。
例如,#define SQUARE(x) ((x) * (x))可以定义一个名为SQUARE的宏函数,用来计算一个数的平方。
C语言宏的使用
C语言宏的使用(转载)2010-03-12 16:19:52| 分类:C语言| 标签:|字号大中小订阅写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等。
下面列举一些成熟软件中常用得宏定义。
1,防止一个头文件被重复包含#ifndef COMDEF_H#define COMDEF_H//头文件内容#endif2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。
typedef unsigned char boolean; /* Boolean value type. */typedef unsigned long int uint32; /* Unsigned 32 bit value */typedef unsigned short uint16; /* Unsigned 16 bit value */typedef unsigned char uint8; /* Unsigned 8 bit value */typedef signed long int int32; /* Signed 32 bit value */typedef signed short int16; /* Signed 16 bit value */typedef signed char int8; /* Signed 8 bit value *///下面的不建议使用typedef unsigned char byte; /* Unsigned 8 bit value type. */typedef unsigned short word; /* Unsinged 16 bit value type. */typedef unsigned long dword; /* Unsigned 32 bit value type. */typedef unsigned char uint1; /* Unsigned 8 bit value type. */typedef unsigned short uint2; /* Unsigned 16 bit value type. */typedef unsigned long uint4; /* Unsigned 32 bit value type. */typedef signed char int1; /* Signed 8 bit value type. */typedef signed short int2; /* Signed 16 bit value type. */typedef long int int4; /* Signed 32 bit value type. */typedef signed long sint31; /* Signed 32 bit value */typedef signed short sint15; /* Signed 16 bit value */typedef signed char sint7; /* Signed 8 bit value */3,得到指定地址上的一个字节或字#define MEM_B( x ) ( *( (byte *) (x) ) )#define MEM_W( x ) ( *( (word *) (x) ) )4,求最大值和最小值#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )5,得到一个field在结构体(struct)中的偏移量#define FPOS( type, field ) \/*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */6,得到一个结构体中field所占用的字节数#define FSIZ( type, field ) sizeof( ((type *) 0)->field )7,按照LSB格式把两个字节转化为一个Word#define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )8,按照LSB格式把一个Word转化为两个字节#define FLOPW( ray, val ) \(ray)[0] = ((val) / 256); \(ray)[1] = ((val) & 0xFF)9,得到一个变量的地址(word宽度)#define B_PTR( var ) ( (byte *) (void *) &(var) )#define W_PTR( var ) ( (word *) (void *) &(var) )10,得到一个字的高位和低位字节#define WORD_LO(***) ((byte) ((word)(***) & 255))#define WORD_HI(***) ((byte) ((word)(***) >> 8))11,返回一个比X大的最接近的8的倍数#define RND8( x ) ((((x) + 7) / 8 ) * 8 )12,将一个字母转换为大写#define UPCASE( 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) <= 'F') ||\((c) >= 'a' && (c) <= 'f') )15,防止溢出的一个方法#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))16,返回数组元素的个数#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )17,返回一个无符号数n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)#define MOD_BY_POWER_OF_TWO( val, mod_by ) \( (dword)(val) & (dword)((mod_by)-1) )18,对于IO空间映射在存储空间的结构,输入输出处理#define inp(port) (*((volatile byte *) (port)))#define inpw(port) (*((volatile word *) (port)))#define inpdw(port) (*((volatile dword *)(port)))#define outp(port, val) (*((volatile byte *) (port)) = ((byte) (val)))#define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))[2005-9-9添加]19,使用一些宏跟踪调试A N S I标准说明了五个预定义的宏名。
宏的使用方法
宏的使用方法宏的使用方法一、定义宏1、定义宏的格式:#define 宏名称(参数) 宏体2、宏体可以是常量、表达式、语句等,通常用于简化一些繁杂的步骤。
3、宏也称为函数,但它和普通函数存在一定的区别:宏定义时会出现宏替换,而函数调用时会进行函数调用。
二、宏的使用1、宏的使用可以分为两种:预处理宏和扩展宏。
2、预处理宏:通常是在源代码中放置宏定义,使用#define宏名称(参数)宏体格式定义宏,然后在源代码中放置宏定义,使用#include<宏名称>调用宏函数,宏会被编译器直接替换为定义的宏体,而不会进行函数调用。
3、扩展宏:与预处理宏相比,扩展宏定义时只需要提供宏函数的定义,而不需要在源代码中放置任何宏定义,使用#define宏名称(参数)宏体格式定义宏,然后使用宏名称(参数)调用宏函数,可以实现宏的更多复杂功能,也可以用来应对编译器的限制和某些场景的特殊要求。
三、注意事项1、宏定义的关键字不能直接引用,如果宏定义中使用到关键字,应该使用##号将关键字拼接起来。
2、宏定义时,参数不要太多,如果参数过多会影响宏体的可读性,容易出错。
3、在宏定义中应该添加注释,特别是对宏体不清楚的地方,这样可以提高代码的可读性和可维护性。
4、在宏定义中应该使用do while(0),这样可以防止在宏函数中出现逻辑问题,比如在使用宏定义实现if else语句时,在使用if else语句时,在宏函数中出现的if else的逻辑错误,do while(0)可以给出一定的保障。
5、在宏定义中避免使用不必要的表达式,不必要的表达式在宏替换时可能会导致编译错误,影响程序运行。
C语言深入分析函数与宏的使用
C语⾔深⼊分析函数与宏的使⽤⽬录⼀、函数与宏⼆、宏的妙⽤三、⼩结⼀、函数与宏宏是由预处理器直接替换展开的,编译器不知道宏的存在函数是由编译器直接编译的实体,调⽤⾏为由编译器决定多次使⽤宏会导致最终可执⾏程序的体积增⼤函数是跳转执⾏的,内存中只有⼀份函数体存在宏的效率⽐函数要⾼,因为是直接展开,⽆调⽤开销函数调⽤时会创建活动记录,效率不如宏下⾯看⼀个函数与宏的⽰例,先看这个程序:#include <stdio.h>#define RESET(p, len) \while( len > 0 ) \((char*)p)[--len] = 0void reset(void* p, int len){while( len > 0 )((char*)p)[--len] = 0;}int main(){int array[] = {1, 2, 3, 4, 5};int len = sizeof(array);int i = 0;RESET(array, len);for(i=0; i<5; i++){printf("array[%d] = %d\n", i, array[i]);}return 0;}输出结果如下:但是如果我们这么写,RESET(6, len); 程序直接出现段错误,都没有给出警告:⽽我们使⽤函数 reset(6, len); 时,则会出现警告:所以说能⽤函数实现的功能就尽可能的不使⽤宏。
宏的效率⽐函数稍⾼,但是其副作⽤巨⼤宏是⽂本替换,参数⽆法进⾏类型检查可以⽤函数完成的功能绝对不⽤宏宏的定义中不能出现递归定义下⾯看⼀个宏的副作⽤的代码:#include <stdio.h>#define _ADD_(a, b) a + b#define _MUL_(a, b) a * b#define _MIN_(a, b) ((a) < (b) ? (a) : (b))int main(){int i = 1;int j = 10;printf("%d\n", _MUL_(_ADD_(1, 2), _ADD_(3, 4)));printf("%d\n", _MIN_(i++, j));return 0;}输出结果如下:按理说输出结果应该是 21 和 1 ,为什么是 11 和 2 呢?下⾯进⾏单步调试,输⼊ gcc -E test.c -o test.i ,得到 test.i ⽂件,部分结果如下:这样就能解释了。
CC++宏的用法
CC++宏的⽤法宏替换是C/C++系列语⾔的技术特⾊,C/C++语⾔提供了强⼤的宏替换功能,源代码在进⼊编译器之前,要先经过⼀个称为“预处理器”的模块,这个模块将宏根据编译参数和实际编码进⾏展开,展开后的代码才正式进⼊编译器,进⾏词法分析、语法分析等等。
我们常⽤的宏替换主要有这么⼏个类型。
1.宏常量在ACM等算法竞赛中,经常会把数组的最⼤下标通过宏定义的⽅法给出,以⽅便调试,例如:#define MAX 1000int array[MAX][MAX]......for(int i = 0; i < MAX; i++)......将⼀个数字定义成全局的常量,这个⽤法在国产垃圾教材上⼗分常见。
但在经典著作《Effective C++》中,这种做法却并不提倡,书中更加推荐以const常量来代替宏常量。
因为在进⾏词法分析时,宏的引⽤已经被其实际内容替换,因此宏名不会出现在符号表中。
所以⼀旦出错,看到的将是⼀个⽆意义的数字,⽐如上⽂中的1000,⽽不是⼀个有意义的名称,如上⽂中的MAX。
⽽const在符号表中会有⾃⼰的位置,因此出错时可以看到更加有意义的错误提⽰。
2.⽤于条件编译标识的宏#define常与#ifdef/#ifndef/defined指令配合使⽤,⽤于条件编译。
#ifndef _HEADER_INC_#define _HEADER_INC_…………#endif这种宏标记在头⽂件中⼗分常见,⽤于防⽌头⽂件被反复包含。
应该养成习惯在每个头⽂件中都添加这种标记。
还有⼀种⽤于条件编译的⽤法#ifdef DEBUGprintf("{“}Debug information\n");#endif通过DEBUG宏,我们可以在代码调试的过程中输出辅助调试的信息。
当DEBUG宏被删除时,这些输出的语句就不会被编译。
更重要的是,这个宏可以通过编译参数来定义。
因此通过改变编译参数,就可以⽅便的添加和取消这个宏的定义,从⽽改变代码条件编译的结果。
cpp宏使用
1 无参宏定义无参宏的宏名后不带参数。
其定义的一般形式为:#define 标识符字符串其中的“#”表示这是一条预处理命令。
凡是以“#”开头的均为预处理命令。
“define”为宏定义命令。
“标识符”为所定义的宏名。
“字符串”可以是常数、表达式、格式串等。
在前面介绍过的符号常量的定义就是一种无参宏定义。
此外,常对程序中反复使用的表达式进行宏定义。
例如:#define M (y*y+3*y)它的作用是指定标识符M来代替表达式(y*y+3*y)。
在编写源程序时,所有的(y*y+3*y)都可由M代替,而对源程序作编译时,将先由预处理程序进行宏代换,即用(y*y+3*y)表达式去置换所有的宏名M,然后再进行编译。
【例】#define M (y*y+3*y)main(){int s,y;printf("input a number: ");scanf("%d",&y);s=3*M+4*M+5*M;printf("s=%d\n",s);}上例程序中首先进行宏定义,定义M来替代表达式(y*y+3*y),在s=3*M+4*M+5* M中作了宏调用。
在预处理时经宏展开后该语句变为:s=3*(y*y+3*y)+4*(y*y+3*y)+5*(y*y+3*y);但要注意的是,在宏定义中表达式(y*y+3*y)两边的括号不能少。
否则会发生错误。
如当作以下定义后:#difine M y*y+3*y在宏展开时将得到下述语句:s=3*y*y+3*y+4*y*y+3*y+5*y*y+3*y;这相当于:3y2+3y+4y2+3y+5y2+3y;显然与原题意要求不符。
计算结果当然是错误的。
因此在作宏定义时必须十分注意。
应保证在宏代换之后不发生错误。
对于宏定义还要说明以下几点:1) 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。
C语言宏的特殊用法和几个坑(转)
C语⾔宏的特殊⽤法和⼏个坑(转)总结⼀下C语⾔中宏的⼀些特殊⽤法和⼏个容易踩的坑。
由于本⽂主要参考GCC⽂档,某些细节(如宏参数中的空格是否处理之类)在别的编译器可能有细微差别,请参考相应⽂档。
宏基础宏仅仅是在C预处理阶段的⼀种⽂本替换⼯具,编译完之后对⼆进制代码不可见。
基本⽤法如下:1. 标⽰符别名#define BUFFER_SIZE 1024预处理阶段,foo = (char *) malloc (BUFFER_SIZE);会被替换成foo = (char *) malloc (1024);宏体换⾏需要在⾏末加反斜杠\#define NUMBERS 1, \2, \3预处理阶段int x[] = { NUMBERS };会被扩展成int x[] = { 1, 2, 3 };2. 宏函数宏名之后带括号的宏被认为是宏函数。
⽤法和普通函数⼀样,只不过在预处理阶段,宏函数会被展开。
优点是没有普通函数保存寄存器和参数传递的开销,展开后的代码有利于CPU cache的利⽤和指令预测,速度快。
缺点是可执⾏代码体积⼤。
#define min(X, Y) ((X) < (Y) ? (X) : (Y))y = min(1, 2);会被扩展成y = ((1) < (2) ? (1) : (2));宏特殊⽤法1. 字符串化(Stringification)在宏体中,如果宏参数前加个#,那么在宏体扩展的时候,宏参数会被扩展成字符串的形式。
如:#define WARN_IF(EXP) \do { if (EXP) \fprintf (stderr, "Warning: " #EXP "\n"); } \while (0)WARN_IF (x == 0);会被扩展成:do { if (x == 0)fprintf (stderr, "Warning: " "x == 0" "\n"); }while (0);这种⽤法可以⽤在assert中,如果断⾔失败,可以将失败的语句输出到反馈信息中2. 连接(Concatenation)在宏体中,如果宏体所在标⽰符中有##,那么在宏体扩展的时候,宏参数会被直接替换到标⽰符中。
宏功能 总结
宏功能总结宏功能是指在计算机程序设计中,将一系列操作或指令封装成一个单元,以便在需要的时候调用执行的能力。
宏功能的使用可以极大地简化代码,提高代码的可读性和可维护性,并且还可以增加程序的灵活性和扩展性。
宏功能主要有以下几个特点:1. 代码的重用性:宏功能可以将一段常用的代码封装起来,可以通过简单的调用来重复使用,避免了重复编写相似的代码,提高代码的复用性。
2. 代码的简洁性:宏功能可以把一系列复杂的操作或指令封装在一个宏中,通过简单的宏调用,就可以完成一系列的操作。
相比于繁琐的代码,宏功能能够使代码更加简洁明了。
3. 提高代码的可读性和可维护性:宏功能将一段代码封装在一个单元中,通过给这个单元起一个有意义的名字,可以大大提高代码的可读性。
此外,如果代码需要修改,只需要修改宏定义的地方,所有调用了这个宏的地方都会自动更新,减少了修改代码的工作量。
4. 增加程序的灵活性和扩展性:宏功能的调用可以根据不同的参数实现不同的功能,通过修改参数的值,就可以实现不同的操作。
这样就增加了程序的灵活性和扩展性,使得程序可以在不同的场景下应对不同的需求。
虽然宏功能具有上述的优点,但是也存在一些潜在的问题和注意事项。
1.代码的膨胀:宏展开可能会导致代码膨胀,使得可执行文件的大小增加。
在使用宏功能时,需要权衡代码的规模和可执行文件的大小,避免过度的代码膨胀。
2.宏定义的作用域:宏定义是全局的,宏展开时会替换所有调用宏的地方。
在使用宏功能时,需要注意宏定义的作用域,避免影响到其他代码段的正确执行。
3.宏展开的副作用:某些宏定义可能会有副作用,即宏展开过程中对变量进行了修改或对外部环境产生了影响。
在使用宏功能时,需要注意副作用可能带来的问题,保证宏的正确使用。
总体来说,宏功能是一种非常有用的编程技术,可以提高代码的重用性、简洁性、可读性、可维护性,以及程序的灵活性和扩展性。
但是在使用宏功能时,也需要注意代码膨胀、作用域和副作用等问题,以保证宏的正确使用。
C++中宏的妙用
C++中宏的妙用1、概述C++中出了const关键字以后,宏定义常量的功能已经不在被推荐使用。
这使得宏似乎没有了用武之地。
实际上,宏还可以做很多事情,笔者也难以全部列举。
这1、概述C++中出了const关键字以后,宏定义常量的功能已经不在被推荐使用。
这使得宏似乎没有了用武之地。
实际上,宏还可以做很多事情,笔者也难以全部列举。
这里,仅仅列举几个典型的用法,希望大家能够从中获益。
2、实现多环境兼容常见的情况是,我们实现了一个函数,希望它只在某种编译条件满足是被编译和使用。
例如,我希望在源码中插入调试语句,以便以Debug方式运行时能够通过调试信息观察程序运行情况。
但是,在产品发售给用户时,我又希望这些调试信息不要输出,以降低代码尺寸,提高运行性能。
这一问题的解决方法就是使用宏。
根据条件编译指令,对于不同的编译条件,提供不同的实现。
例如:我们希望在特定的位置向日志中写入当前行号和文件名,以判断对应代码是否被执行到,可以使用下面的宏:#ifdef _DEBUG#define TRACE_FILE_LINE_INFO() do{CString str;str.Format(_T("file=%s,line=%u",__FILE__,__LINE__);CFile file("logfile.txt");file.Write(str,str.GetLength());}while(0)#else#define TRACE_FILE_LINE_INFO()#endif上面这段代码通过#ifdef #else #endif三个条件编译指令,根据_DEBUG定义情况(该宏用于区分DEBUG版本和Release版本),决定了具体的TRACE_FILE_LINE_INFO宏函数的实现。
使用者可以用如下方法使用TRACE_FILE_LINE_INFO();//这里显示行号和文本信息当然,采用其他方式也可以实现这一功能,但是使用宏有以下特殊好处:只有需要的代码才会被编译,减少了符号表的尺寸,也减少了代码尺寸宏在编译时被展开,因此用于表示代码位置的__FILE__,__LINE__宏可以起作用,如果用函数实现,这两个宏则不能起作用。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include <文件名>
编译时以包含处理以后的文件为编译单位,被包含的文件是源文件的一部分。
li9_6a.c li9_6b.c
编译以后只得到一个目标文件.obj
被包含的文件又被称为“标题文件”或“头部文件”、“头文件”,并且常用.h作扩展名。
修改头文件后所有包含该文件的文件都要重新编译
li9_1.c
说明:(1)宏名一般用大写
(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。
例如:数组大小常用宏定义
(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。
(4)宏定义末尾不加分号;
(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。
#define SQ(x) ((x)*(x))
#define CUBE(x) (SQ(x)*(x))
3.宏定义类函数
宏定义常用于把直接插入的代码来代替函数,以提高执行效率。这一类的宏,就称做宏定义类函数,例如:
#define MIN(x,y) (((x)<(y))?(x):(y))
#include <string.h> /* 串函数文件 */
#include <malloc.h> /* 内存分配函数文件 */
#include <ctype.h> /* 字符函数文件 */
#include <math.h> /* 数学函数库文件 */
用文件包含,可以减少重复工作,提高程序正确性,还便于维护修改。程序员可以把自己常用的一些符号常量、类型定义和带参数的宏定义,以及一些常用自编函数都放在.h文件中,通过#include语句包含引用之。
掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。
即在对相关命令或语句的含义和功能作具体分析之前就要换,“不管三七二十一,先换了再说”。
那么剩下的问题就简单了:
1 把谁换掉?2 换成什么?
#define PI 3.1415926
把程序中出现的PI全部换成3.1415926
的
但是 定义成A(x)后 只有A后面带一个(x)类型的 编译器才会执行替换 比较安全 可以保证只替换函数而不替换变量
第四个
可变参数宏
有些时候定义一个宏来代替某个函数 但是这个函数是可变参数的话 那就需要考虑办法了
定义方法如下
CODE
#define PRINT(...) printf(__VA_ARGS__)
#endif
7.4格式化输入/输出
格式化的控制台I/O函数有两种,它们都与标准I/O库有关。源程序开头应包含标准输入输出头文件:
#include <stdio.h>
area=S(3,2);第一步被换为area=a*b;,第二步被换为area=3*2;
类似于函数调用,有一个哑实结合的过程
li9_3.c
(1)实参如果是表达式容易出问题
#define S® r*r
area=S(a+B);第一步换为area=r*r;,第二步被换为area=a+b*a+b;
#include <stdio.h>
int main(){
PRINT("%d %s %s",1,"吃饭了吗 smile MM:)","\n");
return 0;
}
第五个 宏组合
也就是## 和 #的用法
## 是连接符号 连接两个宏
#是把名字代替成字符串
如下
CODE
头文件的内容除了函数原型和宏定义外,还可以有结构体定义,全局变量定义
(1)一个#include命令指定一个头文件
(2)文件1包含文件2,文件2用到文件3,则文件3的包含命令#include应放在文件1的头部第一行。
(3)包含可以嵌套
(4)<文件名>称为标准方式,系统到头文件目录查找文件
"文件名"则先在当前目录查找,而后到头文件目录查找
(5)被包含文件中的静态全局变量不用在包含文件中声明。
9.3 条件编译
有些语句行希望在条件满足时才编译。
格式:(1)
#ifdef 标识符
程序段1
#else
程序段2
#endif
或
#ifdef
程序段1
#define s5(a) supper_ ## a
#include <stdio.h>
void supper_printf(const char* p )
{
printf("this is supper printf:\n%s\n",a);
}
int main()
{
s5(printf)("hello owrld");
C的预处理主要有三个方面的内容:宏定义、文件包含、条件编译
预处理命令以符号“#”开头。
9.1 宏定义
9.1.1 不带参数的宏定义
宏定义又称为宏代换、宏替换,简称“宏”
格式:
#define 标识符 字符串
其中的标识符就是所谓的符号常量,也称为“宏名”
预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。
#endif
int a(int x)
{
return x+1;
}
int b(int x){
return x+100;
}
int main(){
printf ("A(10) value is %d",A(10));
return 0;
}
[/code]
其实也可以定义成
#define A a
7.1什么是预处理程序
预处理程序是一些行首以#开始的特殊语句,例如:#include,#define等就是预处理语句。在编译程序的编译过程中,进行其它编译处理(词法分析、语法分析、代码生成、优化和连接等)之前,先进行这些语句的分析处理。
预处理语句使用的目的在于帮助程序员编写出易读、易改、易移植并便于调试的程序。预Biblioteka 理语句主要有四种: CODE
#include <stdio.h>
int main()
{
#ifdef _DEBUG
printf("hello world\n");
#else
printf("no debug");
#endif
return 0;
}
第一次使用 gcc -D_DEBUG main.c
printf(PRINT_STR);
return 0;
}
编译时 会把PRINT_STR代替成"你好 DD"
以后想修改时就方便了
另外也可以定义为函数
#include <stdio.h>
#ifdef _DEBUG
#define A(x) a(x)
#else
#define A(x) b(x)
正确的宏定义是#define S® ®*®
(2)宏名和参数的括号间不能有空格
(3)宏替换只作替换,不做计算,不做表达式求解
(4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存
(5)宏的哑实结合不存在类型,也没有类型转换。
(6)函数只有一个返回值,利用宏则可以设法得到多个值
#endif
当标识符已经定义时,程序段1才参加编译。
格式:(2)
#ifndef 标识符
格式:(3)
#if 表达式
li9_7.c
使用条件编译可以使目标程序变小,运行时间变短。
预编译使问题或算法的解决方案增多,有助于我们选择合适的解决方案。
第7章 预处理程序
7.4条件编译
提供条件编译措施使同一源程序可以根据不同编译条件(参数)产生不同的目录代码,其作用在于便于调试和移植。
条件编译控制语句有不同形式,下面分别讨论。
1.#ifdef语句及其使用
一般格式:
#ifdef 标识符
语句块1
#else
语句块2
(2) #include ″文件名″
第一种,用尖括号表示在标准库目录下找该文件;第二种,用双引号表示先在当前目录(源文件所在目录)中找包含文件,若找不到,再到标准库目录中找。系统的标准库文件都是.h文件。例如:
#include <stdio.h> /* 标准输入输出的基本常量和宏或函数文件 */
(6)可以用#undef命令终止宏定义的作用域
(7)宏定义可以嵌套
li9_2.c
(8)字符串""中永远不包含宏
(9)宏定义不分配内存,变量定义分配内存。
9.1.2 带参数的宏
除了一般的字符串替换,还要做参数代换
格式:
#define 宏名(参数表) 字符串
例如:#define S(a,B) a*b
li9_4.c
(7)宏展开使源程序变长,函数调用不会
(8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)
li9_5.c
分析该例中的"