一、预处理指令
预处理指令是以#号开头的代码行,#号必须是该行除了任何空白字符外的第一个字符。# 后是指令关键字,在关键字和 # 号之间允许存在任意个数的空白字符,整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。
指令 | 含义 |
# | 空指令,没有任何效果 |
#include | 引入一个源文件 |
#define | 定义宏 |
#undef | 取消已定义的宏 |
#ifdef | 如果宏已经定义,则编译下面代码 |
#ifndef | 如果宏没有定义,则编译下面代码 |
#if | 如果给定条件为真,则编译下面代码 |
#elif | 如果前面的#if给定条件不为真,当前条件为真,则编译下面代码 |
#endif | 结束一个#if.....#else条件编译块 |
#include<stdio.h>#if _WIN64 // 如果是windows平台,则执行 #include<math.h>
#include<math.h>
#elif __linux__ // 如果是linux平台,则执行 #include<string.h>
#include<string.h>
#endifint main(){#if _WIN64double a = 2;printf("%f", pow(a, 3)); #elif __linux__ char *str = "C语言";printf("%d", strlen(str)); #endifreturn 0;
}
二、宏定义
#define 叫做宏定义命令,它是C语言预处理命令的一种,在编译之前就处理完成了,不占用内存。
1. 不带参数的宏定义
宏定义就是用一个标识符来表示一个字符串,如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。宏定义只是字符串替换
#define 宏名 字符串
(1)#表示这是一条预处理命令,所有的预处理命令都以#开头。
(2)宏名是标识符的一种,命名规则和变量相同,宏名为大写。
(3)字符串可以是数字、表达式、if 语句、函数等,这里所说的字符串是一般意义上的字符序列,和C语言中的字符串不一样,它不需要双引号。
(4)#define在定义时没有数据类型,在参与运算时只是简单的替换。
(5)宏定义必须写在函数之外。
(6)代码中的宏名如果被引号包围,那么预处理程序不对其作宏代替
(7)可以用宏表示数据类型,宏定义表示数据类型和用 typedef 定义数据类型的区别:宏定义只是简单的字符串替换,由预处理器来处理;而 typedef 是在编译阶段由编译器处理的,它并不是简单的字符串替换,而给原有的数据类型起一个新的名字,将它作为一种新的数据类型
(6)程序中反复使用的表达式就可以使用宏定义。
#include<stdio.h>#define A 4
#define X A
#define B A - 2
#define C (A - 2)
#define D A / B * 3
#define E A / C * 3#define UNIT unsigned int int main(){// #define在定义时没有数据类型,在参与运算时只是简单的替换。printf("X = %d \n", X); // 4printf("D = %d \n", D); // A / A - 2 * 3 = -5printf("E = %d \n", E); // A / (A - 2) * 3 = 6int F = B + E;printf("F = %d \n", F); // A - 2 + A / (A - 2) * 3 = 8// 代码中的宏名如果被引号包围,那么预处理程序不对其作宏代替printf("X \n"); // X// 可以用宏表示数据类型UNIT a = 1; // unsigned int a = 1UNIT b = a + 2;printf("b = %d \n", b); // b = 3return 0;
}
define可以配合#undef(取消定义)、#ifdef(如果定义了,必须与#endif配合使用)、 #ifndef(如果没有定义,必须与#endif配合使用)、#endif 来使用,可以让代码更加灵活
#include<stdio.h>#define PI 3.14
#undef PI //取消定义
#define PI 3.1415926 //再次定义int main(){#ifdef PIprintf("PI = %f\n", PI); // PI = 3.1415926#endif#ifndef PIprintf("PI未定义");#endifreturn 0;
}
2. 带参数的宏定义
在宏定义中的参数称为“形参”,在宏调用中的参数称为“实参”,与函数有些类似,但是形参不用指明参数类型,实参需要指明参数类型。对带参数的宏,在展开过程中不仅要进行字符串替换,还要用实参去替换形参。
#define 宏名(形参列表) 字符串 // 注意:宏名和(形参列表)之间不能有空格
带参宏调用的一般形式为:宏名(实参列表)
字符串内的形参通常要用括号括起来以避免出错
#include<stdio.h>#define MAX(a, b) (a > b) ? a : b
#define SQ1(c) c * c // 字符串内的形参通常要用括号括起来以避免出错
#define SQ2(c) (c) * (c)int main(){int x = 2; int y = 3;int max = MAX(x, y); // int max = (x > y) ? x : y 不仅要进行字符串替换,还要用实参去替换形参printf("%d \n", max); // 3int res1 = SQ1(x + 1); // x + 1 * x + 1printf("%d \n", res1); // 5 int res2 = SQ2(x + 1); // (x + 1) * (x + 1)printf("%d \n", res2); // 9 return 0;
}