一 预定义符号
语言内置的符号,可以用来查看被编辑文件的状态
有以下几种:
__FILE__ 被编辑的源文件
__LINE__被编辑文件所在行
__DATE__被被编辑文件的日期
__TIME__被编辑文件的时间
__STDC__编译器是否遵循ABSI C,若遵循为1,否则未定义(vs中未定义)
对上述预定义符号的示例:
二 #define
1 #define定义的标识符
#define name stuff
stuff的种类多样,可以是常量表达式,可以是关键字名字,可以是函数,可以是代码段……
接下来做演示
①常量
#define _crt_secure_no_warnings 1
#include<stdio.h>
#define number 1000
int main()
{
printf("%d", number);//1000
return 0;
}
也可以是常量表达式
②函数:
#define _crt_secure_no_warnings 1
#include<stdio.h>
#include<stdlib.h>
#define m malloc//宏可以定义关键字和函数等但是要申明头文件
int main()
{
int i = 0;
int* p = (int*)m(sizeof(int) * 10);
if (p != null)
{
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", *p);
p++;
}
}
free(p);
p = null;
return 0;
}
③关键字
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define I int
int main()
{
I a = 10;
printf("%d ", a);
return 0;
}
④某种功能的实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
int a = 10;
int b = 20;
printf("%d", MAX(a, b));
return 0;
}
2 定义宏
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define MALLOC(number,type) (type*)malloc(number*sizeof(type))
int main()
{
int i = 0;
int* p = MALLOC(10, int);
if (p != NULL)
{
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
# if 0
for (i = 0; i < 10; i++)
{
printf("%d ", *p);
p++;
}
#endif
}
return 0;
}
注意:
①末尾不能加上;否则编译器会认为是;;
②尽量多的带上(),因为#define执行的是替换操作,尽量在每个参数和整体都带上()
③应该避免使用++这类带有副作用的代码,比如i++最好写成i+1
④由于宏定义的是常量,所以不能递归
⑤预处理器搜索#define定义的符号的时候,字符串常量的内容不会被搜索
⑥在“”内的宏不会被替换
3#define替换规则
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先
被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上
述处理过程。
4 # 与##
简单来说,#执行的是插入操作,##执行的是连接操作
举例子,对于#的插入操作
#define _crt_secure_no_warnings 1
#include<stdio.h>
#define VALUE(number,value) printf("the value of"#number"is%d",value)
int main()
{
VALUE(a, 10);
VALUE(b, 20);
}
对于##连接操作
#define PEO_INFO(n) class##n
5 宏和函数的对比
①执行速度:宏相对来说快,因为函数有调用和返回的额外开销
②代码长度:宏每次都被替换,函数只调用一次
③参数类型:宏的参数与类型无关,可以用于任何参数类型,但是不易控制
④调试:宏不方便调试,函数可以逐语句调试
⑤递归:宏不能递归
命名约定:宏名全部大写,函数名不要全部大写
三#undef
用于移除宏定义,重新定义
举例:
#define _crt_secure_no_warnings 1
#include<stdio.h>
#define number 1000
#undef number//移除宏定义以及宏再次定义
#define number num
#define num 1000
int main()
{
printf("%d", number);
return 0;
}
四条件编译
选择性编译
1单分支条件编译
#if
……
#endif
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define MALLOC(number,type) (type*)malloc(number*sizeof(type))
int main()
{
int i = 0;
int* p = MALLOC(10, int);
if (p != NULL)
{
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
# if 0
for (i = 0; i < 10; i++)
{
printf("%d ", *p);
p++;
}
#endif
}
return 0;
}
2多分支条件编译
用法类似 #if #elif #else #endif
3判断是否被定义
#if defined()
#ifdef
用法差不多,都是表达被定义的时候要做什么
不过取反的话,对于 #if defined()-》#if !defined() 对于#ifdef -》#ifndef
上述的条件编译语句可以嵌套
五 文件包含
有两种方式
①#include<>
对于这种形式,查找直接去标准路径下查找
②#include“”
对于这种形式,先去源文件所在目录下查找,再去标准位置找
当然都使用“”理论上没有问题,但是效率会下降,也不容易区分库文件和本地文件
对于嵌套文件包含
用#pragma once可以解决