1、翻译环境
在代码执行前,会将源文件转化为可执行的机器指令
2、预处理详解
2.1 预定义符号
预定义符号是语言内置的符号可以直接使用
__FILE__ //进行编译的源文件
__LINE__ //文件的当前行
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义
一般在写日志的时候会用到
2.2 #define
2.2.1 #和##
#:把一个宏参数变成对应的字符串
#include <stdio.h>
#define PRINT(n) printf("the value of "#n" is %d\n",n )
int main()
{
int a = 10;
PRINT(a);
int b = 20;
PRINT(b);
return 0;
}
##: 把位于它两端的符号合成一个符号
#include <stdio.h>
#define CAT(s,num) s##num
int main()
{
int sum5 = 2;
int b = CAT(sum, 5);//sum5
printf("%d", b);
return 0;
}
2.2.2 宏与函数
1、代码长度
宏:每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长
函数:函数的代码只出现与一个地方;每次使用这个函数时调用的是同一份代码
2.执行速度:
宏:更快
函数:函数的调用和返回需要额外开销,相对来说会慢一点
3.操作符优先级
宏:宏使用的时候是直接替换,如果没加括号的话,可能会因为优先级问题参数预料之外的结果
函数:函数在传参前先求值
4.带有副作用的参数(自加自减)
宏:参数可能被替换到宏体的多个位置
比如:
#include <stdio.h>
#define MAX(x,y) (x)>(y)?(x):(y)
int main()
{
int a = 2;
int b = 3;
int m = MAX(a++, b++);
return 0;
}
a、b会进行多次自增操作
函数:只在传参的时候计算一次
5.参数类型
宏:宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型
#include <stdio.h>
#define MALLOC(type,size) (type*)malloc(sizeof(type)*size);
int main()
{
int* p = MALLOC(int, 5);
return 0;
}
函数:传参的参数需要与定义是的参数对应
6.调试
宏:宏是预处理阶段的操作,不便于调试
函数:可以逐句调试
7.递归
宏:不能递归
函数:可以递归
2.3 #undefine
移除一个宏定义
2.4 命令行定义
许多C 的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程。
#include <stdio.h>
int main()
{
int array [ARRAY_SIZE];
int i = 0;
for(i = 0; i< ARRAY_SIZE; i ++)
{
array[i] = i;
}
for(i = 0; i< ARRAY_SIZE; i ++)
{
printf("%d " ,array[i]);
}
printf("\n" );
return 0;
}
编译指令
//linux 环境演示
gcc -D ARRAY_SIZE=10 programe.c
2.5 条件编译
一些调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译。
#include <stdio.h>
#define __DEBUG__
int main()
{
int i = 0;
int arr[10] = {0};
for(i=0; i<10; i++)
{
arr[i] = i;
#ifdef __DEBUG__
printf("%d\n", arr[i]);//为了观察数组是否赋值成功。
#endif //__DEBUG__
}
return 0;
}
多分支条件编译
#include <stdio.h>
#define M 150
int main()
{
#if M<100
printf("less\n");
#elif M==100
printf("==\n");
#elif M>100
printf("more\n");
#else
printf("hehe\n");
#endif
return 0;
}
判断是否被定义
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define M 150
int main()
{
#if defined(M)//如果定义了为真
printf("hehe\n");
#endif
#ifdef m//如果定义了为真
printf("haha\n");
#endif
#if !defined(m)//如果没定义为真
printf("wangwang~\n");
#endif
#ifndef M//如果没定义为真
printf("miaomiao~\n");
#endif
}
嵌套指令
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();
#endif
#endif
2.6 文件包含
" ":先在源文件所在目录下查找,如果该头文件未找到,编译器就会在标准位置查找头文件,如果找不到就报错
<>:直接在标准路径下查找,如果找不到就报错
解决当多次包含同一个头文件时只包含一次
1.
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif
2.
#pragma once