深入网站开发和运维 pdf,桂林市区好玩的地方,网站模板缺少文件怎么办,中文建站模板宏
宏名称通常都是由大写英文字母构成的宏名称里不可以包含空格用宏给数字起名字的时候不可以使用赋值运算符#xff0c;不要自增自减可以在编写程序的时候直接使用宏名称替代数字#xff0c;编译器在编译的时候会把程序里的宏替换成它所代表的数字
1. 为什么要使用宏#x…宏
宏名称通常都是由大写英文字母构成的宏名称里不可以包含空格用宏给数字起名字的时候不可以使用赋值运算符不要自增自减可以在编写程序的时候直接使用宏名称替代数字编译器在编译的时候会把程序里的宏替换成它所代表的数字
1. 为什么要使用宏
1.1 名称直观
宏可以用有意义的名称比如使用PI去替代抽象的数值3.14让代码更易懂。开发者看到PI时能直接联想到“圆周率”而无需记忆数字的含义尤其是在复杂程序中这种直观性能显著提高代码的可理解性。
1.2 便于更新
当需要修改宏代表的值时如PI的精度从3.14调整为3.14159只需在宏定义处修改一次编译器会在预处理阶段自动替换所有引用该宏的地方。如果不使用宏直接在代码中多出写死数值修改时需要逐个查找并替换不仅繁琐还容易遗漏增加出错风险。
2. 无参宏基本宏
#includestdio.h// 定义无参宏PI代表圆周率3.14159
// 宏的作用用有意义的名称替代常量提高代码可读性
// 后续若需调整精度如改为3.1415926只需修改此处即可所有引用处会自动替换
#define PI (3.14159)int main(void){float r 0;printf(请输入一个半径值:);scanf(%f,r);// 计算圆的面积使用宏PI替代3.14159代码更直观printf(圆的面积是:%g\n, PI * r * r);// 计算圆的周长同样使用宏PI确保所有圆周率值一致printf(圆的周长是:%g\n, 2 * PI * r);return 0;
}3. 带参宏类似函数的宏
带参宏的特性仅在预处理阶段做文本替换不进行参数类型检查适用于多种数据类型
#includestdio.h// 定义带参宏SQUARE用于计算参数的平方
// 宏参数x表示要计算平方的数值或表达式
// 替换文本((x)*(x))外层和内层都加括号是为了避免因运算符优先级导致的计算错误
#define SQUARE(x) ((x)*(x)) int main(void){// 调用带参宏SQUARE参数为整数5// 预处理阶段会替换为((5)*(5))结果为25printf(%d\n, SQUARE(5));// 调用带参宏SQUARE参数为浮点数5.5// 预处理阶段会替换为((5.5)*(5.5))结果为30.25// 体现宏不检查类型的特性可同时处理整数和浮点数printf(%lg\n, SQUARE(5.5));// 调用带参宏SQUARE参数为表达式23// 预处理阶段会替换为((23)*(23))结果为25// 因宏定义中参数x被括号包裹避免了23*23的错误计算printf(%d\n, SQUARE(23));return 0;
}4. 编译时定义宏通过编译选项
无需在代码中用#define定义可通过编译器选项-D在编译时指定宏的值
适用于需要根据不同场景如调试/发布版本、不同硬件配置动态修改宏值的场景
语法gcc -D 宏名值 源文件 -0 输出文件
例如gcc -DSIZE10 test.c -o test定义SIZE为10
也可以gcc -D SIZE10 test.c -o test定义SIZE为10
// 代码中无需定义SIZE编译时通过-D指定
#includestdio.h
int main(void){int arr[SIZE] {}; // SIZE由编译选项指定for(int i0; iSIZE; i){arr[i] i 100;}for(int i0; iSIZE; i){printf(%d , arr[i]);}return 0;
}5. 宏运算符
#将宏的参数转换为字符串字符串化。
例#define STR(x) #x则STR(123)会替换为123。##将两个标识符连接为一个新的标识符连接符。
例#define JOIN(a,b) a##b则JOIN(num,1)会替换为num1。
#include stdio.h// 1. #运算符将宏参数转换为字符串字符串化
#define STR(x) #x // 定义宏STR使用#将参数x转换为字符串// 2. ##运算符将两个参数连接为一个新的标识符连接符
#define JOIN(a, b) a##b // 定义宏JOIN使用##连接a和b为新标识符int main(void) {// 测试#运算符printf(使用#运算符的结果\n);printf(STR(123) %s\n, STR(123)); // 替换为123输出字符串123printf(STR(abc) %s\n, STR(abc)); // 替换为abc输出字符串abcprintf(STR(3.14) %s\n, STR(3.14)); // 替换为3.14输出字符串3.14// 测试##运算符printf(\n使用##运算符的结果\n);int num1 100; // 定义变量num1int num2 200; // 定义变量num2printf(JOIN(num, 1) %d\n, JOIN(num, 1)); // 连接为num1输出100printf(JOIN(num, 2) %d\n, JOIN(num, 2)); // 连接为num2输出200// ##运算符也可用于函数名或其他标识符int student10 95; // 定义变量student10printf(JOIN(student, 10) %d\n, JOIN(student, 10)); // 连接为student10输出95return 0;
}
6. 预定义宏编译器自带预定义宏占位符含义__FILE__%s所在文件名__func__%s所在函数名__LINE__%d所在行号__DATE__%s编译该文件日期__TIME__%s编译该文件时间注意前后都是两个下划线
#includestdio.h
int main(void){int* p NULL;int a 10;//p a;if(p NULL){printf(指针为NULL\n);// 把一个大串拆成多个小串编译器会自动拼接相邻字符串// 以下使用C语言预定义宏输出调试信息printf(文件:%s\n // __FILE__预定义宏所在文件名函数:%s\n // __func__预定义宏所在函数名行号:%d\n // __LINE__预定义宏所在行号日期:%s\n // __DATE__预定义宏编译该文件日期时间:%s\n, // __TIME__预定义宏编译该文件时间__FILE__, __func__, __LINE__, __DATE__, __TIME__);return -1; // 默认意外退出返回-1}return 0; // 正常退出返回0
}