c语言的宏定义:宏定义单纯的文本替换不会检查语法是否合法
#include #pragma 以及开头的#都属于预处理指令
预处理指令:在gcc编译套件中的cpp预处理器对程序进行编译之前所做的一些动作,如#include预处理指令就是在程序编译之前有预处理器吧包含头文件中的代码拷贝一份到源文件的对应位置,如果包含的文件中还有其他预处理指令,会递归执行
c标准中还提供了#define预处理指令,具有定义含义
定义格式:#define 宏名称(一般大写) 替换列表 换行
在程序编译前,预处理器会把宏用替换列表替换,只是单纯替换文本,不做任何语法检查。
#include <stdio.h>
#define M 5
#define N M+M
int main()
{
int k;
k = N*N*5; //M+M*M+M*5 = 5+5*5+5*5=55
printf("k=%d\n", k); //55
return 0;
}
#include <stdio.h>
#define N 2
#define M N+1
// NUM => (N+1+1)*N+1/2 =>(N+2)*N+1/2
#define NUM (M+1)*M/2
int main()
{
int i = 0;
while(i < NUM)
{
printf("%d", i++); //01234567
}
printf("\n");
return 0;
}
宏定义的作用域是针对整个文件有效,所以应该定义在源文件的开头部分,这样才可以在其他的函数中使用宏定义,宏不是语句,索引不需要末尾添加分号。若添加分号则分号也会被一起替换。
宏定义方案:无参数宏,带参数宏,无替换宏
无参数定义宏:
_ _DATA_ _:输出日期
_ _FILE_ _:输出文件信息
_ _LINE_ _:输出当前行数
带参数定义宏:
定义宏输出两个数较大的数/较小的数
#include <stdio.h>
#define MAX(a,b) (((a) > (b)) ? (a):(b))
#define MIN(a,b) (((a) < (b)) ? (a):(b))
int main(void)
{
printf("max is %d\n", MAX(4,3));
printf("min is %d\n", MIN(4,3));
return 0;
}
定义宏不使用第三参数,交换两个数:
#include <stdio.h>
#define SWAP(a,b) {a=a+b; b=a-b; a=a-b;}
int main(void)
{
int a=3,b=4;
printf("交换前a=%d, b=%d\n", a, b);
SWAP(a,b);
printf("交换后a=%d, b=%d\n", a, b);
return 0;
}
带参宏会在程序所有出现的位置进行展开,缺点是浪费的内存空间,但是节约了参数切换的时间
计算字符串中连续相同的字符个数:
#include <stdio.h>
int max_strlen(char *s)
{
int max = 1; //存储最大重复字符数量
int count = 1; //计数器
while(*s != '\0') //当未到字符串末尾时进入循环
{
//统计字符重复次数
if(*s == *(s+1)) //对比当前字符与后一个字符是否相等
{
count++; //相等计数加1
}
else
{
max = (max > count) ? max : count; //计数器与最大重复对比
count = 1; //重新计数
}
s++;
}
return max;
}
int main(void)
{
printf("%d\n", max_strlen("aaaadddffjjdddddd")); // 6
return 0;
}
将字符串str_src中的内容拷贝到str_dest中
#include <stdio.h>
void str_copy(const char *str_src, char *str_dest)
{
while(*str_src != '\0')
{
*str_dest++ = *str_src++;
}
*str_dest = '\0';
}
int main(void)
{
char str[128] = {0};
str_copy("hello wordfff", str);
printf("%s\n", str);
return 0;
}
判断大小端存储模式
#include <stdio.h>
union
{
int num;
char s;
}data;
int main(void)
{
data.num = 0x12345678;
if(data.s == 0x12)
{
printf("data.s=%#x, 大端存储\n", data.s);
}
else
{
printf("data.s=%#x, 小端存储\n", data.s);
}
return 0;
}
定义函数宏,求x平方
#include <stdio.h>
#define SQURE(x) ((x)*(x))
int main(void)
{
printf("5*5=%d\n", SQURE(5));
return 0;
}
无替换列表的宏
c语言中也允许只定义一个宏,这个宏可以没有替换列表,一般实际开发中都是对程序进行条件表一的情况来使用
#if 用于判断常量表达式是否成立,遵循非0即真原则,作为条件编译,#if预处指令必须配合#endf指令使用
#if #ifdef #elif #else #endif
#ifdef :判断宏是否被定义,若被定义则预处理指令是有效的
#ifndef 代码块 #endif :判断宏是否被定义,若没被定义则代码快被保留
#ifndef,#define,#endif:预处理指令,用于条件编译,可以防止头文件重复包含
宏定义一般在源文件开头,作用域为整个文件,#undef可以提前终止宏的作用域
程序的编译过程:
hello.c =cpp=> 预处理hello.i(文本)=ccl=>编译hello.s(文本)=as=>汇编hello.o(二进制)+libc标准库==>链接hello(二进制)
预处理:对源代码进行简单加工,GCC编译器会调用预处理器cpp对程序进行预处理==》解释源程序中所有的预处理指令,如#include、#define、等以#开头的预处理语句,预处理指令会在预处理阶段被解释掉,同步把所有的注释删除,生成.i文件
编译:对预处理之后的 .i 文件进一步翻译,生成.s文件
汇编:GCC编译器调用汇编器as将汇编文件翻译成可重新定位的文件,生成.o文件
链接:生成可执行文件