宏是用来表示一段代码的标识符。
三种用法:
预定义宏 | 作用 |
---|---|
FILE | 表示当前源文件 |
LINE | 当前所在文件的行号 |
DATE | 文件被编译的日期 |
TIME | 文件被编译的时间 |
实例
#include
int main() {
printf("%s:%d\n",__FILE__,__LINE__); //当前源文件:当前所在文件的行号
printf("%s:%s\n",__DATE__,__TIME__); //文件被编译的日期:文件被编译的时间
}
#define 标识符 值
#define PI 3.1415926
带参数的宏:宏可以带参数,使用上有些像函数。
语法:#define 标识符(参数...) 代码
实例:#define square(x) ((x)*(x))
#include
#define square(x) x*x
int main() {
printf("%d\n",square(10));
printf("%d\n",square(10+1));
}
100
21 <== 10+1*10+1
注:宏定义缺少括号导致宏定义边际效应,所以带参数的宏需要在以下两个位置加上括号:
1、参数出现的每个地方都要加括号。
2、整个值要加括号。
#include
#define HELLO_WORLD \
"Hello World"
#define NUM 5
#define square(x) ((x)*(x))
#define SWAP(a,b) \
int t = a; \
a = b; \
b = t;
#define MAX(a,b) ((a)>(b)?(a):(b))
int main() {
char* s = HELLO_WORLD;
printf("%s\n",s);
int arr[NUM];
int a = 10,b = 20;
printf("a:%d\tb:%d\n",a,b);
SWAP(a,b);
printf("a:%d\tb:%d\n",a,b);
printf("%d\n",MAX(a,b));
printf("%d\n",square(10));
printf("%d\n",square(10+1));
}
有时我们会使用没有值的宏,这种宏用于条件编译的,#ifdef #ifndef
用于检查宏是否被定义过。控制代码的编译。
实例:
#include
#define TEST
int main(){
#ifdef TEST
printf("123\n");
#else
printf("abc\n");
#endif
}
123
以#
开头的都是编译预处理指令。除了宏定义,还有文件包含#include
和条件编译指令#if、#ifdef #ifndef、#else、#elif
。
#include
#if、#ifdef #ifndef、#else、#elif
#include指令
.h
中,在需要调用这个函数的源代码文件.c
时,使用#include
指令包含这个头文件,使编译器在编译的时候知道函数的原型。在使用和定义函数的地方都要#include
头文件。例如我们常用的stdio.h
#include
指令不一定要放在.c
文件的最前面,但是通常习惯这样做。
#include
指令分类#include <>
:编译器到指定目录查找,主要用于查找标准库的头文件。#include ""
:编译器先到当前目录查找(.c文件所在目录),如果没有再到指定目录查找。注:#include
指令是一个编译预处理指令,和宏一样,在编译之前就处理了。它会把指定的文件原封不动的插入到它所在的地方。
头文件通常用来存放所有对外公开的函数的原型和全局变量的声明。
通常任何.c文件都有对应同名的.h文件。
常见的声明:
函数声明
变量声明
结构声明
宏声明
枚举声明
类型声明
注:声明通常只能可以放在头文件中,否则,编译器连接会出现重名函数错误。
#include
导致重复声明。int i;// 变量的定义
extern int i; // 变量的声明
区别:声明是不产生代码的语句。定义是产生代码的语句。
避免头文件多次包含,必须使用标准头文件结构。
#ifndef _文件名_H__
#define _文件名_H__
// 声明
#endif
使用条件编译和宏,保证头文件在一个编译单元中只会#include
一次。
注:#pragma once
指令与上述代码作用相同,但是并不是所有编译器支持。
误区:
1、#include
不是用来引入库的
2、头文件只有函数原型,函数实现在.a(Unix)
或者.lib(Windows)
中。
3、现代的C语言编译器会默认引入所有的标准库。
1、 PrintArr.c
和PrintArr.h
#include
#include "PrintArr.h"
void PrintArr(int* arr,int n){
for(int i = 0;i < n;++i){
printf("%d ",arr[i]);
}
printf("\n");
}
void PrintArr(int* arr,int n);
2、 DesSort.c
和DesSort.h
#include
#include "DesSort.h"
#include "PrintArr.h"
int cmp(const void* a,const void* b){
return *(int*)a<*(int*)b ? 1:-1;
}
void DesSort(int* arr,int n){
qsort(arr,n,sizeof(int),cmp);
PrintArr(arr,n);
}
int cmp(const void* a,const void* b);
void DesSort(int* arr,int n);
3、test.c
#include
#include "PrintArr.h"
#include "DesSort.h"
int main(){
int arr[] = {1,2,3,4,5};
PrintArr(arr,5);
DesSort(arr,5);
}
编译:gcc test.c PrintArr.c DesSort.c -o main