前言:C预处理在程序执行之前查看程序(称之为预处理器)。根据程序中的预处理指令,预处理器把符号替换成其表示的内容。本篇主要是为了写“大程序结构”作准备,其中包含了宏的说明和基本用法,还有#include"",或#include<>的区别,还有”标准头文件结构“
一、编译预处理和宏
1、编译预处理指令
- #开头是编译预处理指令;
- 它们不是C语言的成分,但C语言程序离不开它们
- #define用来定义一个宏
2、宏的说明和基本用法
1)例子:
/* #define <名字> <值> */
#define PI 3.14 //一般名字都用全大写
- 注意没有结尾的分号,因为不是C语句
- 名字必须是一个单词,值可以是各种东西(等会儿会举例)
- 在C语言的编译器开始编译之前,编译预处理程序会把程序中的名字替换成值
- 注意:这里是完全的文本替换
- 如果一个宏的值中有其它宏的名字,也是会被替换的
- 如果一个宏的值超过一行,最后一行之前的行末加‘\‘
- 宏值后面出现的注释不会被当作宏的一部分
2)没有值的宏
#define _DEBUG
这类宏是用于条件编译的,后面有其它的编译预处理指令来检查这个宏是否已被定义过了;
3)带参数的宏的原则
#define SQUAER(x) ((x)(x))//这是一个类宏函数,实现平方的功能
#define MIN(a,b) ((a)>(b)?(a):(b)) //可以带多个参数
- 一切参数都要括号
- 整个值要括号
- 参数出现的每个地方都要括号
应用场景:
- 在大型程序的代码中使用非常普遍
- 可以非常复杂,如"产生"函数
二、大程序结构
1、多个源代码文件
多个.c文件,
- main( )里的代码太长了适合分成几个函数
- 一个源代码太长了适合分成几个文件
- 两个独立的源代码文件不能编译成可执行的程序
2、项目
- 在Dev C++中新建一个项目,然后把几个源代码文件加入进去
- 对于项目,Dev C++的编译会把一个项目中所有的源代码都编译后,链接起来
- 有的IDE有分开的编译和构建两个按钮,前者是对单个源代码文件编译,后者是对整个项目做链接
3、编译单元
- 一个C文件时一个编译单元
- 编译器每次只能处理一个编译单元
4、头文件(可以看成是一个合同)
- 把函数原型放到一个头文件(以.h结尾)中,在需要调用这个函数的源代码文件(.c)中#include(引用)这个头文件,就能让编译器在编译时知道函数的原型
5、#include“ "、还是#include<>
- #include有两种形式来指出要插入的文件
- " "要求编译器首先在当前目录(.c文件所在的目录)寻找这个文件,如果没有,到编译器指定目录去找
- < >让编译器只能在指定目录去找
- 编译器知道自己的标准库的头文件在哪里
- 环境变量和编译器命令行参数也可以指定寻找头文件的目录
6、标准头文件结构
为了避免重复声明结构,例子:
//name.h --修订后的name_st头文件,避免重复
#ifndef NAMES_H_
#define NAMES_H_
//多个.c文件共用的宏可以写在头文件程序里
#define SLEN 32
//多个.c文件共用的变量也可以写在头文件里
extern int i;
//结构声明
struct names_st{
char first[SLEN];
char last[SLEN];
};
//类型定义
typedef struct name_st names;
//函数原型
void get_names(names *);
void show_names(const names *);
char * s_gets(char * st, int n)l
#endif
注:
- 运用条件编译和宏,保证这个头文件在编译单元只能被#include一次;
- #pragma once起同样效果,但不是所有编译器都支持;