【C语言】编译预处理指令、define、宏、项目、头文件

文章目录

  • 编译预处理指令
  • define
    • 有值的宏
    • 没有值的宏
    • 预定义的宏
    • 带参数的宏
  • 多个源代码文件
    • 项目
    • 编译单元
  • 头文件
    • 不对外公开的函数
    • 头文件的声明和定义
    • #include
      • #include后的“”和<>
      • #include的误区
    • 避免头文件的重复声明——标准头文件结构
  • 变量的声明
    • 声明和定义


编译预处理指令

① #开头的是编译预处理指令
② 它们不是C语言的成分,但是C语言程序离不开它们
③ #define用来定义一个宏

#define PI 3.14159  
/*这行define在定义一个符号,把这样一个定义叫做宏,
PI是这个宏的名字,3.14159是这个宏的值*/

printf("%f\n",PI*3);//3.14159*3
/*C语言在所有编译之前进行编译预处理,
把程序里的所有PI都替换成后面的数值3.14159*/

define

#define <名字> <值>
① 注意没有结尾的分号,因为不是C的语句;
② 名字必须是一个单词,值可以是各种东西;
③ 在C语言的编译器开始编译之前,编译预处理程序(compile-preprocess,cpp)会把程序中的名字换成值,把出现了定义的宏的名字的地方都替换成后面的那个值;
④ 完全的文本替换。

宏中的数据参数都是没有类型的;
宏结尾不要加分号。

#define FORMAT "%f\n"
#define PI 3.14159  
/*这两行define在定义一个符号,把这样一个定义叫做宏,
format是这个宏的名字,%f\n是这个宏的值
PI是这个宏的名字,3.14159是这个宏的值*/

printf(FORMAT,PI*3);//3.14159*3
/*C语言在所有编译之前进行编译预处理,
把程序里的所有"%f\n"替换成FORMAT,
所有PI都替换成后面的数值3.14159*/

有值的宏

① 如果一个宏的值中有其他的宏的名字,也是会被替换的;
② 如果一个宏的值超过一行,最后一行之前的行末需要加 \ ;
③ 宏的值中出现的任何标点符号都会被当作宏的值的一部分;
④ 宏的值后面出现的注释不会被当作宏的值的一部分。

#define FORMAT "%f\n"
#define PI 3.14159 
#define PI2 2*PI

printf(FORMAT,PI+PI2);//3.14159+2*3.14159

没有值的宏

eg:#define _DEBUG
这类宏是用于条件编译的,后面有其他的编译预处理指令来检查这个宏是否已经被定义过了。

预定义的宏

一般用来表达一些特殊的东西,让编译器插入一些特殊的值。

常用:
LINE:文件当前的行号
FILE:进行编译的源文件的名字
DATE:文件被编译的日期(格式:mmm dd yyyy)
TIME:文件被编译的时间(格式:hh: mm: ss)
……
【注意:前后分别是两个短杠】

#include
int main(){
	printf("%s:%d\n",__FILE__,__LINE__);
	printf("%s,%s\n",__DATE__,__TIME__);
	return 0;
}

带参数的宏

#include
#define cube(x) ((x)*(x)*(x))//带参数的宏
int main(){
	printf("%d\n",cube(5));
	return 0;
}

输出:125
  • 带参数的宏的原则:

一切都要括号:整个值要括号;参数出现的每个地方都要括号。
eg:#define RADTODEG(x) ((x)*57.29578)

  • 可以带多个参数:

eg:#define MIN(a,b) ((a)>(b)?(b):(a))
也可以组合(嵌套)使用其他宏

  • 特点:

在大型程序的代码中使用非常普遍;
可以非常复杂,如“产生”函数,在#和##这两个运算符的帮助下;
部分宏会被inline函数替代,inline可以做参数检查。

多个源代码文件

main()里的代码太长了适合分成几个函数;
一个源代码文件太长了适合分成几个文件;
两个独立的源代码文件不能编译形成可执行的程序。

项目

① 在Dev C++中新建一个项目,然后把几个源代码文件加入进去;
② 对于项目,Dev C++的编译会把一个项目中所有的源代码文件都编译后,链接起来;
③ 有的IDE有分开的编译和构建两个按钮,前者是对单个源代码文件编译,后者是对整个项目做链接。

例:这个项目有两个文件

main.c文件

#include
int max(int a,int b);//函数声明
int main(void){
	int a=5;
	int b=6;
	printf("%d\n",max(a,b));
	return 0;
}

max.c文件

int max(int a,int b)
{
	return a>b?a:b;
}

编译单元

一个.c文件是一个编译单元;
编译器每次编译只处理一个编译单元。

头文件

① 把函数原型放到一个头文件(以.h结尾)中,在需要调用这个函数的源代码文件(.c文件) 中#include这个头文件,就能让编译器在编译的时候知道函数的原型;

例:

max.h头文件

int max(int a,int b);

main.c文件

#include
#include"max.h"

int main(void){
	int a=5;
	int b=6;
	printf("%d\n",max(a,b));
	return 0;
}

max.c文件

#include"max.h"
int max(int a,int b)
{
	return a>b?a:b;
}

② 在使用和定义这个函数的地方都应该#include这个头文件;一般的做法就是任何.c都有对应的同名的.h,把所有对外公开的函数的原型和全局变量的声明都放进去。

全局变量是可以在多个.c之间共享的。

不对外公开的函数

① 在函数前面加上static就使得它成为只能在所在的编译单元中被使用的函数;
② 在全局变量前面加上static就使得它成为只能在所在的编译单元中被使用的全局变量。

头文件的声明和定义

一般情况下,头文件只能声明变量或函数,不能定义变量或函数。因为头文件要被其他文件包含#include,如果把定义放在头文件的话,就有可能出现多次定义变量或函数造成错误。一个程序中对指定变量或函数的定义只有一次,声明可以又多次。

头文件可以定义变量或函数的情况:
① 只有一个.c或.cpp文件包含了这个头文件;
② 头文件中可以定义const或者static修饰的变量或函数;
③ 可以定义类。

#include

① #include是一个编译预处理指令,和宏一样,在编译之前就处理了;
它把那个文件的全部文本内容原封不动地插入到它所在的地方(#include只做这一件事情,其它的什么都不做),所以也不是一 定要在.c文件的最前面#include。

#include后的“”和<>

#include有两种形式来指出要插入的文件:“”和<>
① “”要求编译器首先在当前目录(.c文件所在的目录)寻找这个文件,如果没有,到编译器指定的目录去找;
② <>让编译器只在指定的目录去找
编译器自己知道自己的标准库的头文件在哪里;
环境变量和编译器命令行参数也可以指定寻找头文件的目录。

#include的误区

① #include不是用来引入库的,它把那个文件的全部文本内容原封不动地插入到它所在的地方(#include只做这一件事情,其它的什么都不做)
② stdio.h里只有printf的原型,printf的代码在另外的地方,某个.lib(Windows)或.a(Unix)中。
③ 现在的C语言编译器默认会引入所有的标准库#include只是为了让编译器知道printf函数的原型,保证你调用时给出的参数值是正确的类型。

有时候没有引入头文件,但是编译运行都正确了,这是因为编译器会猜测,猜测对了就运行正确。
就像函数里面的参数类型,如果没有输入参数类型,编译器默认猜测int,如果匹配,则运行正确。

避免头文件的重复声明——标准头文件结构

同一个编译单元里,同名的结构不能被重复声明;
如果你的头文件里有结构的声明,很难这个头文件不会在一个编译单元里被#include多次,所以需要“标准头文件结构”。

标准头文件结构:

#ifndef _LIST_HEAD__ //检查,如果没有定义则下一步定义,如果已经定义了则不再定义
#define _LIST_HEAD__ //如果没有定义,于是就定义这个头文件
……
……(定义的东西)
……
#endif //定义完成则执行#endif后面的语句

运用条件编译和宏,保证这个头文件在一个编译单元中只会被#include一次;
#pragma once也能起到相同的作用,但是不是所有的编译器都支持。

变量的声明

声明不用初始化,初始化是定义做的事情。

int i;//是变量的定义
extern int i;//加一个extern关键字,这是变量的声明

声明和定义

声明是不产生代码的东西
函数原型、变量声明、结构声明、宏声明、枚举声明、类型声明、inline函数。

定义是产生代码的东西
函数、全局变量。


你可能感兴趣的:(C语言,c语言,c#,c++,算法,开发语言)