c++宏详解
详解C语言的宏定义

详解C语⾔的宏定义宏定义介绍假设我们有⼀个 C 源⽂件 main.c,那么只需要通过 gcc main.c -o main.exe 即可编译成可执⾏⽂件(如果只写 gcc main.c,那么 Windows 上会默认⽣成 a.exe、Linux 上会默认⽣成 a.out ),但是这⼀步可以拆解成如下步骤:预处理:gcc -E main.c -o main.i,根据 C 源⽂件得到预处理之后的⽂件,这⼀步只是对 main.c 进⾏了预处理:⽐如宏定义展开、头⽂件展开、条件编译等等,同时将代码中的注释删除,注意:这⾥并不会检查语法;编译:gcc -S main.i -o main.s,将预处理后的⽂件进⾏编译、⽣成汇编⽂件,这⼀步会进⾏语法检测、变量的内存分配等等;汇编:gcc -c main.s -o main.o,根据汇编⽂件⽣成⽬标⽂件,当然我们也可以通过 gcc -c main.c -o main.o 直接通过 C 源⽂件得到⽬标⽂件;链接:gcc main.o -o main.exe,程序是需要依赖各种库的,可以是静态库也可以是动态库,因此需要将⽬标⽂件和其引⽤的库链接在⼀起,最终才能构成可执⾏的⼆进制⽂件。
⽽这⾥我们主要来介绍⼀下预处理中的宏定义,相信很多⼈都觉得宏定义⾮常简单,但其实宏定义有很多⾼级⽤法。
我们先来看看简单的宏定义:#include <stdio.h>// 宏定义的⽅式为:#define 标识符常量// 然后会将所有的 PI 替换成 3.14#define PI 3.14int main() {printf("%f\n", PI);}我们⽣成预处理之后的⽂件:gcc -E main.c -o main.i我们看到 PI 被替换成了 3.14,当然除了浮点型之外,也可以是其它的类型:#include <stdio.h>#define NAME "satori"#define AGE 17#define GENDER 'f'int main() {printf("%s %d %c\n", NAME, AGE, GENDER); // satori 17 f}我们再来查看⽣成的预处理⽂件:我们看到确实只是简单替换,除此之外,没有做任何的处理。
C语言:代码宏详解

C语⾔:代码宏详解⽬录1、定义宏2、宏函数3、多⾏宏4、宏变长参数5、原样输出变量名6、例⼦7、宏与函数的差异总结1、定义宏#define ARRAY_SIZE 100double data[ARRAY_SIZE];如下图,上⽅代码在编译器进⾏宏替换时会将代码中的ARRAY_SIZE替换成1002、宏函数宏函数的参数是没有任何类型的概念的,因此宏函数使⽤如下,代码中的MAX(3,4)会替换成宏定义的表达式#define MAX(a,b) a > b ? a : bint n1 = MAX(3,4);注意上⽅替换出错,是因为给宏函数的参数传递的是⼀个表达式,可以使⽤下图⽅法宏函数的参数不要传表达式,如下图,表达式进⾏了2次运算3、多⾏宏使⽤斜杠连接下⼀⾏代码,适⽤于代码很长的宏#define IS_HEX_CHARACTOR(ch) \( (ch) >= '0' && (ch) <= '9') || \( (ch) >= 'A' && (ch) <= 'F') || \( (ch) >= 'a' && (ch) <= 'f')int main(){printf("is hex charactor:%d", IS_HEX_CHARACTOR('a'));}4、宏变长参数#define PRINTLNF(format, ...) printf(format, __VA_ARGS__)5、原样输出变量名6、例⼦#include <stdio.h>#define PRINTF(format, ...) printf("("__FILE__":%d) %s: "format,__LINE__,__FUNCTION__, ##__VA_ARGS__) #define PRINT_INT(value) PRINTF(#value":%d \n", value)int main(){int no = 1;PRINT_INT(no);return 0;}7、宏与函数的差异总结本篇⽂章就到这⾥了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!。
c语言 宏函数

C语言宏函数一、什么是宏函数在C语言中,宏函数是一种在代码中被预先定义的简单的文本替换机制。
当代码中出现宏函数的调用时,编译器会将宏函数的名称和参数替换为宏函数定义中所指定的文本,从而实现宏函数的功能。
二、宏函数的定义和使用宏函数的定义使用#define关键字,语法格式如下:#define 宏函数名(参数列表) 替换文本其中,宏函数名是用户自定义的宏函数名称,参数列表包含宏函数的参数,替换文本是宏函数的真正执行内容。
宏函数可以在任何需要的地方使用,它的使用方式和普通的函数调用非常相似。
例如:宏函数名(参数列表)三、宏函数的优缺点3.1 优点•宏函数在编译时会进行简单的文本替换,不需要函数的调用开销,执行效率高。
•宏函数不会增加新的函数调用栈,避免了函数调用的内存开销。
•宏函数可以实现代码的重用,降低代码量,提高可维护性。
3.2 缺点•宏函数的替换是简单的文本替换,没有类型检查,可能导致参数类型不匹配的问题。
•宏函数的替换会增加代码的长度,可能导致可读性下降。
•宏函数的定义一旦出错,会在编译期间就报错,增加了调试的难度。
四、宏函数的应用场景4.1 常量定义宏函数可以用于定义常量,例如:#define PI 3.14159这样,在代码中就可以直接使用宏函数PI来表示圆周率,而不需要重复输入具体的数值。
4.2 算术运算宏函数可以用于简单的算术运算,例如:#define SQUARE(x) ((x) * (x))这样,在代码中就可以使用宏函数SQUARE来计算平方,例如:int result = SQUARE(5); // 结果为254.3 条件编译宏函数可以用于条件编译,例如:#define DEBUG#ifdef DEBUG// 执行调试相关的代码#else// 执行发布版本的代码#endif这样,可以根据是否定义了宏函数DEBUG来选择性地编译不同的代码。
4.4 字符串拼接宏函数可以用于字符串的拼接,例如:#define CONCAT(a, b) a##bchar str[] = CONCAT("Hello", "World"); // 结果为"HelloWorld"五、宏函数的注意事项•宏函数的参数使用时需要加上括号,以防止由于运算符优先级引起的错误。
C 语言宏详解

代码自动生成-宏带来的奇技淫巧Pdf制作:jmpesp@byr Author : Kevin Lynx众多C++书籍都忠告我们C语言宏是万恶之首,但事情总不如我们想象的那么坏,就如同goto 一样。
宏有一个很大的作用,就是自动为我们产生代码。
如果说模板可以为我们产生各种型别的代码(型别替换),那么宏其实可以为我们在符号上产生新的代码(即符号替换、增加)。
关于宏的一些语法问题,可以在google上找到。
相信我,你对于宏的了解绝对没你想象的那么多。
如果你还不知道#和##,也不知道prescan,那么你肯定对宏的了解不够。
我稍微讲解下宏的一些语法问题(说语法问题似乎不妥,macro只与preprocessor有关,跟语义分析又无关):1. 宏可以像函数一样被定义,例如:#define min(x,y) (x<y?x:y) //事实上这个宏存在BUG但是在实际使用时,只有当写上min(),必须加括号,min才会被作为宏展开,否则不做任何处理。
2. 如果宏需要参数,你可以不传,编译器会给你警告(宏参数不够),但是这会导致错误。
如C++书籍中所描述的,编译器(预处理器)对宏的语法检查不够,所以更多的检查性工作得你自己来做。
3. 很多程序员不知道的#和###符号把一个符号直接转换为字符串,例如:#define STRING(x) #xconst char *str = STRING( test_string ); str的内容就是"test_string",也就是说#会把其后的符号直接加上双引号。
##符号会连接两个符号,从而产生新的符号(词法层次),例如:#define SIGN( x ) INT_##xint SIGN( 1 ); 宏被展开后将成为:int INT_1;4. 变参宏,这个比较酷,它使得你可以定义类似的宏:#define LOG( format, ... ) printf( format, __VA_ARGS__ )LOG( "%s %d", str, count );__VA_ARGS__是系统预定义宏,被自动替换为参数列表。
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语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等。
下面列举一些成熟软件中常用得宏定义: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 bitvalue */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)))19,使用一些宏跟踪调试A N S I标准说明了五个预定义的宏名。
C语言宏定义详解

C语言宏定义详解我们可能要定义很多常量( 不管是放在源文件还是头文件 ),那么我们有时考虑定义某个常量时,我们就必须返回检查原来此常量是否定义,但这样做很麻烦.if defined宏正是为这种情况提供了解决方案.举个例子,如下:#define ....#define ....................#define a 100.......此时,我们要检查a是否定义(假设我们已经记不着这点了),或者我们要给a一个不同的值,就加入如下句子#if defined a#undef a#define a 200#endif上述语句检验a是否被定义,如果被定义,则用#undef语句解除定义,并重新定义a为200 同样,检验a是否定义:#ifndef a //如果a没有被定义#define a 100#endif以上所用的宏中:#undef为解除定义,#ifndef是if not defined的缩写,即如果没有定义。
这就是#if defined 的唯一作用常用宏定义总结*pclint////////////////////////////////// #include <stdio.h>////////////////////////////////#define VPLS_EXT_DEBUG 1#if VPLS_EXT_DEBUG#define _VE_DEBUG(msg...) printf("[VPLS_DEBUG] %s,%d => ",__FILE__, __LINE__);printf(msg);printf("\r\n")#else#define_VE_DEBUG(x1,x2) (void)(x1),(void)(x2)#endif调用直接写为_VE_DEBUG("XXXXX %d",adb)开关关闭后这句直接失效//////////////////////////////main(void){ int a,b,c,d; a = b = c = d = 9;_BUG("a = %d,b = %d,c = %d,d = %d\n",a,b,c,d);}#define assert(e)\ ((void)((e) || fprintf(stderr,"line %d: 'asserterror!'\n",__LINE__)))////////////////////////////////////__attribute__ 作用- -__attribute__ 是GCC的关键字,描述变量的属性。
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. 宏的替换文本不要使用分号。
因为宏的替换是简单的文本替换,如果在替换文本中加上分号,会导致使用宏的地方出现多余的分号,从而引发编译错误。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
c/c++宏的使用总结在这里总结宏的使用方法欢迎补充1 条件include如下CODE#ifndef MAIN_H_#define MAIN_H_其它内容#endif上面在看到头文件时会看到作用就是阻止这个头文件被多次include多次include就会出现重复的定义情况所以需要在每个头文件中都使用这个定义如果还不是很了解要怎样使用可以看看 c的标准头文件如fcntl.h2 条件编译如下CODE#ifdef _DEBUGprintf("this debug info\n");#endif如果没有定义_DEBUG宏的话那么上面那一行是不会编译进去的但是定义了_DEBUG后上面那行就会编译进去可以写个简单的程序测试CODE#include <stdio.h>int main(){#ifdef _DEBUGprintf("hello world\n");#elseprintf("no debug");#endifreturn 0;}第一次使用 gcc -D_DEBUG main.c第二次使用 gcc main.c运行两次的结果看3 定义为某个值以便后面修改这个值时不用修改其它地方代码只要修改这个宏的定义就可以了如一个软件的多语言版本等如下CODE#include <stdio.h>#define PRINT_STR "你好 DD"main(){printf(PRINT_STR);return 0;}编译时会把PRINT_STR代替成"你好 DD"以后想修改时就方便了另外也可以定义为函数#include <stdio.h>#ifdef _DEBUG#define A(x) a(x)#else#define A(x) b(x)#endifint 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但是定义成A(x)后只有A后面带一个(x)类型的编译器才会执行替换比较安全可以保证只替换函数而不替换变量第四个可变参数宏有些时候定义一个宏来代替某个函数但是这个函数是可变参数的话那就需要考虑办法了定义方法如下CODE#define PRINT(...) printf(__VA_ARGS__)#include <stdio.h>int main(){PRINT("%d %s %s",1,"吃饭了吗 smile MM:)","\n");return 0;}第五个宏组合也就是## 和 #的用法## 是连接符号连接两个宏#是把名字代替成字符串如下CODE#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");return 0;}#用法如下#include <stdio.h>#define s(p) #pint main(){printf(s(p)"\n");return 0;}运行一下就知道了最后附上网上找到的宏定义的概念第一篇第九章预处理命令预处理的概念:编译之前的处理C的预处理主要有三个方面的内容:宏定义、文件包含、条件编译预处理命令以符号“#”开头。
9.1 宏定义9.1.1 不带参数的宏定义宏定义又称为宏代换、宏替换,简称“宏”格式:#define 标识符字符串其中的标识符就是所谓的符号常量,也称为“宏名”预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。
掌握"宏"概念的关键是“换”。
一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。
即在对相关命令或语句的含义和功能作具体分析之前就要换,“不管三七二十一,先换了再说”。
那么剩下的问题就简单了:1 把谁换掉?2 换成什么?#define PI 3.1415926把程序中出现的PI全部换成3.1415926li9_1.c说明:(1)宏名一般用大写(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。
例如:数组大小常用宏定义(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。
(4)宏定义末尾不加分号;(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。
(6)可以用#undef命令终止宏定义的作用域(7)宏定义可以嵌套li9_2.c(8)字符串""中永远不包含宏(9)宏定义不分配内存,变量定义分配内存。
9.1.2 带参数的宏除了一般的字符串替换,还要做参数代换格式:#define 宏名(参数表)字符串例如:#define S(a,B) a*barea=S(3,2);第一步被换为area=a*b;,第二步被换为area=3*2;类似于函数调用,有一个哑实结合的过程li9_3.c(1)实参如果是表达式容易出问题#define S® r*rarea=S(a+B);第一步换为area=r*r;,第二步被换为area=a+b*a+b;正确的宏定义是#define S® ®*®(2)宏名和参数的括号间不能有空格(3)宏替换只作替换,不做计算,不做表达式求解(4)函数调用在编译后程序运行时进行,并且分配内存。
宏替换在编译前进行,不分配内存(5)宏的哑实结合不存在类型,也没有类型转换。
(6)函数只有一个返回值,利用宏则可以设法得到多个值li9_4.c(7)宏展开使源程序变长,函数调用不会(8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)li9_5.c分析该例中的"9.2 “文件包含”处理一个文件包含另一个文件的内容格式:#include "文件名"或#include <文件名>编译时以包含处理以后的文件为编译单位,被包含的文件是源文件的一部分。
li9_6a.c li9_6b.c编译以后只得到一个目标文件.obj被包含的文件又被称为“标题文件”或“头部文件”、“头文件”,并且常用.h作扩展名。
修改头文件后所有包含该文件的文件都要重新编译头文件的内容除了函数原型和宏定义外,还可以有结构体定义,全局变量定义(1)一个#include命令指定一个头文件(2)文件1包含文件2,文件2用到文件3,则文件3的包含命令#include应放在文件1的头部第一行。
(3)包含可以嵌套(4)<文件名>称为标准方式,系统到头文件目录查找文件"文件名"则先在当前目录查找,而后到头文件目录查找(5)被包含文件中的静态全局变量不用在包含文件中声明。
9.3 条件编译有些语句行希望在条件满足时才编译。
格式:(1)#ifdef 标识符程序段1#else程序段2#endif或#ifdef程序段1#endif当标识符已经定义时,程序段1才参加编译。
格式:(2)#ifndef 标识符格式:(3)#if 表达式li9_7.c使用条件编译可以使目标程序变小,运行时间变短。
预编译使问题或算法的解决方案增多,有助于我们选择合适的解决方案。
第7章预处理程序7.1什么是预处理程序预处理程序是一些行首以#开始的特殊语句,例如:#include,#define等就是预处理语句。
在编译程序的编译过程中,进行其它编译处理(词法分析、语法分析、代码生成、优化和连接等)之前,先进行这些语句的分析处理。
预处理语句使用的目的在于帮助程序员编写出易读、易改、易移植并便于调试的程序。
预处理语句主要有四种:宏定义和宏替换、文件包含、条件编译和行控制。
预处理语句的作用范围是从被定义语句开始直至被解除定义或是到包含它的文件结术为止均有效。
7.2宏定义和宏替换“宏”是借用汇编语言中的概念。
为的是在C语言程序中方便的作一些定义和扩展。
这些语句以#define 开头,分为两种:符号常量的宏定义和带参数的宏定义。
1.符号常量的宏定义和宏替换符号常量的宏定义语句是一般格式:#define 标识符字符串其中标识符就叫作宏名称。
注意:标识符与字符串之间不要用‘=’,结尾不要加‘;’。
2.带有参数的宏定义及其替换复杂的宏定义带有参数列表,参数列表中可有不止一个参数,其一般格式:#define 标识符(参数列表) 字符串对带有参数的宏定义进行宏替换时,不仅对宏标识符作字符串替换,还必须作参数的替换。
例如:#define SQ(x) ((x)*(x))那么SQ(a+B)将被宏替换成(a+B)*(a+B)。
宏定义也可嵌套使用,即一个宏定义可用另一个宏定义来定义。
例如:#define SQ(x) ((x)*(x))#define CUBE(x) (SQ(x)*(x))3.宏定义类函数宏定义常用于把直接插入的代码来代替函数,以提高执行效率。
这一类的宏,就称做宏定义类函数,例如:#define MIN(x,y) (((x)<(y))?(x):(y))有了这样的宏之后,就可以直接引用,例如:m=MIN(a,B);这语句将被预处理成:m=(((a)<(B))?(a):(B));7.3文件包含文件包含是指一个程序文件将另一个指定义文件的内容包含进来,用#include语句来说明。
一般有两种格式:(1) #include <文件名>(2) #include ″文件名″第一种,用尖括号表示在标准库目录下找该文件;第二种,用双引号表示先在当前目录(源文件所在目录)中找包含文件,若找不到,再到标准库目录中找。
系统的标准库文件都是.h文件。
例如:#include <stdio.h> /* 标准输入输出的基本常量和宏或函数文件 */#include <string.h> /* 串函数文件 */#include <malloc.h> /* 内存分配函数文件 */#include <ctype.h> /* 字符函数文件 */#include <math.h> /* 数学函数库文件 */用文件包含,可以减少重复工作,提高程序正确性,还便于维护修改。