C语言源文件要经过编译、链接才能生成可执行程序:
编译是针对单个源文件的,一次编译操作只能编译一个源文件,如果程序中有多个源文件,就需要多次编译操作。
在实际开发中,有时候在编译之前还需要对源文件进行简单的处理。
例如: 不同的环境下系统的头文件定义和函数名有所不同,比如说:假如现在要开发一个C语言程序,让它暂停 5 秒以后再输出内容,并且要求跨平台,在 Windows 和 Linux 下都能运行,怎么办呢?
这个程序的难点在于,不同平台下的暂停函数和头文件都不一样:
不同的平台下必须调用不同的函数,并引入不同的头文件,否则就会导致编译错误,因为 Windows 平台下没有 sleep() 函数,也没有
#include
//不同的平台下引入不同的头文件
#if _WIN32 //识别windows平台
#include
#elif __linux__ //识别linux平台
#include
#endif
int main() {
//不同的平台下调用不同的函数
#if _WIN32 //识别windows平台
Sleep(5000);
#elif __linux__ //识别linux平台
sleep(5);
#endif
puts("hello jei");
return 0;
}
当此函数在linux环境下编译时经预处理后等同于:
#include
#include
int main() {
sleep(5);
puts("hello jie");
return 0;
}
这些在编译之前对源文件进行简单加工的过程,就称为预处理(即预先处理、提前处理)。
包含另一源文件,到当前源文件中立即在指令下一行的位置。
在系统目录下搜索文件
在用户自定目录下搜索文件,如果未找到再到(1)下找
注意:
#define简但的字符串替换
#include "stdio.h"
//define N 100
#define STR "liujie"
int main(){
int a[N] = {};
printf("%lud ",sizeof (a));
puts(STR);
return 0;
}
//root@VM-Ali-ubuntu:~/tmp/LinuxC# gcc -DN=10 main.c -o main && ./main
//40d liujie
带变元的宏:
#include "stdio.h"
#define ABS(x) (x)>0?(x):-(x)
int main(){
printf("%d ", ABS(2-3));
return 0;
}
#运算符,通常称为stringifie(字符串化)运算符,使得在它后面的变元转换成带双引号的串
#include
#define mkstr(s) #s
int main(void) {
printf(mkstr(I Like C));
return 0;
}
// >>I like C
##操作符,称为 pasting(粘贴,链接)运算符,用于连接两个符号
#include
#define concat(a,b) a##b
int main(void) {
int xy = 10;
printf("%d",concat(x,y)); //宏的哑实结合不存在类型,也没有类型转换。
// printf("%x",concat("hello","tulun"));
return 0;
}
//>>10
#@的功能是将其后面的变元进行字符化VS环境下有效
#include
#define TO_CHAR(x) #@x
int main() {
printf("%c", TO_CHAR(1));
printf("%c", TO_CHAR(3));
printf("%c", TO_CHAR(4));
printf("%c", TO_CHAR(5));
return 0;
}
#undef 指令解除定义 标识符 ,即它取消先前 #define 对 标识符 的定义。若标识符无与之关联的宏,则忽略此指令。
例:
__FILE__
//展开成当前文件名,为字符串常量, 可用 #line 指令更改
__LINE__
//展开成源文件行号,为整数常量, 可用 #line 指令更改
__DATE__
//展开成翻译的日期,格式为 “mm dd yyyy” 的字符串常量。若月之日期小于 10 则 “dd” 的首 //字符为空格
__TIME__
//展开成翻译的时间,格式为 “hh:mm:ss” 的字符串常量
__STDC__
//如果编译器遵循ANSI C,展开成整数常量1,否则未定义。判断当前的编译器是否为标 准C编译器
__func__
//在每个函数体内,拥有块作用域和静态存储期的预定义数组 func 可用, //它如同立即通过以下方式定义void fun() { static const char __func__[]="fun"; }
//C++ 添加的宏定义
__cplusplus
//代表所用的 C++ 标准版本,展开成值
例:
#include
#include
int main() {
printf("%s\n",__FILE__);
printf("%d\n",__LINE__);
printf("%s\n",__DATE__);
printf("%s\n",__TIME__);
printf("%s",__func__);
return 0;
}
///*/root/tmp/LinuxC/cmake-build-debug/LinuxC
///root/tmp/LinuxC/main.c
//7
//Jul 16 2022
//09:44:14
//main*/
例:
#include
#include
#include
#define ASSERT(exp) (void)((exp) || (my_assert(#exp,__FILE__,__LINE__,__func__),0))
void my_assert(const char * _Message,char * _file,int _line,char const* func){
printf("%s:",_file);
printf("%d ",_line);
printf("%s: ",func);
printf("Assertion \'%s\' failed \n",_Message);
abort();
}
void print( int * arr,int n){
ASSERT(arr!=NULL);
// assert(arr!=NULL);
for(int i = 0;i<n;i++){
printf("%d ",arr[i]);
}
}
int main() {
int arr[] = {1,2,3,4,5,6,7,8};
int n = 8;
int * ip = NULL;
print(ip,n);
return 0;
}
条件指令允许你对程序源代码的各部分有选择地进行编译,这个过程称为条件编译。商业软件公司
广泛应用条件编译来提供和维护某一程序的许多定制版本。
#if constant-expression // 常量表达式
statement sequence // 语句序列
#endif
#include
#define TED 10
int main (void) {
#ifdef TED
printf("Hi Ted \n");
#else
printf("Hi anyone \n");
#endif
#ifndef RALPH
printf("RALPH not defined\n");
#endif
return 0;
}
#ifdef defined MYFILE
//或 #ifdef MYEILE
#include
#include
#include
#line 100 "jie.c"
#error "编译出错"
#define ASSERT(exp) (void)((exp) || (my_assert(#exp,__FILE__,__LINE__,__func__),0))
void my_assert(const char * _Message,char * _file,int _line,char const* func){
printf("%s:",_file);
printf("%d ",_line);
printf("%s: ",func);
printf("Assertion \'%s\' failed \n",_Message);
abort();
}
void print( int * arr,int n){
ASSERT(arr!=NULL);
// assert(arr!=NULL);
for(int i = 0;i<n;i++){
printf("%d ",arr[i]);
}
}
int main() {
#ifdef ASSERT
printf("%d ",1);
#endif
int arr[] = {1,2,3,4,5,6,7,8};
int n = 8;
int * ip = NULL;
print(ip,n);
return 0;
}
// /root/tmp/LinuxC/cmake-build-debug/LinuxC
// 1 jie.c:111 print: Assertion 'arr!=NULL' failed
// 进程已结束,退出代码134
------------------------------------------------------------------------------------------------------------
==============================[ 构建 | LinuxC | Debug ]=====================================
///usr/bin/cmake --build /root/tmp/LinuxC/cmake-build-debug --target LinuxC -- -j 6
//Scanning dependencies of target LinuxC
//[ 50%] Building C object CMakeFiles/LinuxC.dir/main.c.o
-------------------------------------
//jie.c:100:2: error: #error "编译出错"
-------------------------------------
//make[3]: *** [CMakeFiles/LinuxC.dir/build.make:63: CMakeFiles/LinuxC.dir/main.c.o] Error 1
//make[2]: *** [CMakeFiles/Makefile2:76: CMakeFiles/LinuxC.dir/all] Error 2
//make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/LinuxC.dir/rule] Error 2
//make: *** [Makefile:118: LinuxC] Error 2
首页 > C语言入门 > 预处理命令
C++中文 - API参考文档
腾讯课堂->全部课程IT·互联网后台开发C/C++C语言入门到进阶