预处理
目录预定义符号
__FILE__ //当前编译的文件名
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__FUNCTION__ //当前所在函数的函数名
//以上格式占用符都用%s,如printf("%s",__DATE__);
__LINE__ //文件当前的行号,格式占用符用%d,如:printf("%d",LINE);
/*注意以上这些宏定义的前后分别有两个'_',而不是一个下划线*/
_CRT_SECURE_NO_WAENINGS//关闭安全检查
宏定义
宏定义:又称为宏替换,自定义一个宏(要符合标识符的命名规则),用于替换任意数据/标识符/表达式。
作用:对源程序编译之前做一些处理,生成扩展C源程序
l种类
•宏定义 #define
•文件包含 #include
•条件编译 #if--#else--#endif等
l格式:
•“#”开头
•占单独书写行
•语句尾不加分号
1.不带参数宏定义
•一般形式: #define 宏名 [宏体]
•功能:用指定标识符(宏名)代替字符序列(宏体)
定义位置:任意(一般在函数外面)
作用域:从定义命令到文件结束
undef可终止宏名作用域
格式: #undef 宏名
宏定义可以嵌套,不能递归
例 #define MAX MAX+10 (错)
#include<stdio.h>
#define YES 1//y原作用域
int main()
{
//......
}
#undef YES
#define YES 0//y新作用域
max()
{
//......
}
宏展开:预编译时,用宏体替换宏名--不作语法检查
(引号中的内容与宏名相同也不置换)
//例:
#define PI 3.14159
printf(“2*PI=%f\n”,PI*2);
//宏展开:
printf(“2*PI=%f\n”,3.14159*2);
2.带参数宏定义
•一般形式: #define 宏名(参数表) 宏体
宏名与参数表之间不能加空格
//例
#define S(a,b) a*b
......
area=S(3,2);
宏展开:area=3*2;
//例
#define POWER(x) x*x
x=4; y=6;
z=POWER(x+y);
宏展开:z=x+y*x+y;
//因此,使用带参数的宏定义的时候注意宏体的形式,注意括号的使用
一般写成: #define POWER(x) ((x)*(x))
宏展开: z=((x+y)*(x+y));
//例 用宏定义和函数实现同样的功能
//宏定义表达形式
#define MAX(x,y) (x)>(y)?(x):(y)
......
main()
{ int a,b,c,d,t;
......
t=MAX(a+b,c+d);
......
}
宏展开:t=(a+b)>(c+d)?(a+b):(c+d);
//函数形式
int max(int x,int y)
{ return(x>y?x:y);
}
main()
{ int a,b,c,d,t;
......
t=max(a+b,c+d);
......
}
带参宏 | 函数 | |
---|---|---|
处理时间 | 编译时 | 程序运行时 |
参数类型 | 无类型问题 | 定义实参,形参类型 |
处理过程 | 不分配内存简单的字符置换 | 分配内存,先求实参值,再代入形参 |
程序长度 | 变长 | 不变 |
运行速度 | 不占用运行时间 | 调用和返回占用时间 |
文件包含
使用用库函数就需要包含头文件,也就是文件包含,可以编写自定义头文件,包含自己编写的头文件。
文件包含的基本格式
include<文件名>或#include"文件名"
#include<stdio.h>//包含系统的头文件用<>,只会在系统头文件找
#include"name.h"//包含自定义头文件用""(在自定义头文件中找不到就会在系统头文件中找)
//文件包含允许嵌套,即在一个被包含文件中可以包含其他文件。
头文件的定义和使用
//头文件的定义需要两个文件来创建(头文件声明,源文件定义)
1.在解决方案资源管理器中右键头文件创建一个新的头文件命名为···.h,例:text.h
在这个头文件中只负责声明函数,不负责定义
2.在源文件中创建同名文件为···.c,例:text.c
这个源文件负责定义函数
3.在主要的文件中调用头文件。例:#include"text.h"
#注意事项
如果头文件A包含头文件C,同时头文件B也包含头文件C,而写的程序中包含了头文件A,头文件B,然后在编译的时候就会出现头文件C重复包含的错误.
这种错误叫做头文件的重复包含。
1.使用#pragma once可以解决这个问题(vs独有,有平台限制)(在自己编写的头文件中使用,而不是源文件)
2.头文件加#ifndef 宏名 #define 宏名 #endif
两者区别:
(1)#ifndef 和#pragma once都发生在预处理阶段,#ifndef的方式依赖于宏名字不能冲突,这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。当然,缺点就是如果不同头文件的宏名不小心“撞车”。
(2)#ifndef是C/C++语言特性,而#pragma once是编译器提供的指令,同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。
(3)#pragma依赖于编译器,所以一些老的编译器不提供(比如说vc6之前),而#ifndef可移植性非常好。
文件text.h:
目的:为了避免同一个文件被include多次
#pragma once //防止头文件的重复包含产生冲突
#ifndef __TEXT_H__//防止一个源文件两次包含同一个头文件
#define __TEXT_H__
/*文件名叫什么就宏定义为大写的格式:*/
/*例:文件name.h->宏定义#ifndef __NAME_H__ #define __NAME_H__ */
void fun();//函数的声明,头文件只能在这个文件中声明
......其他函数
#endif//文件结束
!!后面两个文件的后缀是.c而不是.cpp,不然会报错
条件编译
if #else #ifdef #ifndef
使用方法:
#if+条件(真/假)
代码: 。。。。。。(如果为真,则运行这些代码)
#else
代码: 。。。。。。(如果为假,则运行这些代码)
#endif(结束)注意#endif不可缺少**
#ifdef A(如果定义了A)
#ifndef A(如果没有定义A)
上面两个语句可以代替#if
标签:__,文件,宏名,头文件,定义,预处理,define
From: https://www.cnblogs.com/ningcode/p/17058808.html