一、编译过程
(源代码)–>【预处理】–>(宏替换之后的源代码)–>【编译器】–>(中间文件)–>【链接器】–>(可执行程序)
二、自己定义头文件
引入自己定义的头文件
- 可以使用例如#inclue"…/head/xx.h",使用""会优先查找当前源文件的目录
- 例如在A文件中使用定义好的B文件,直接引入B头文件,而B头文件中只有声明,B的.c文件中是具体实现,并且B的.c文件引入了B的头文件
- 之所以能够通过B的头文件找到B的.c文件是因为.c文件被添加到了工程之中
三、宏函数
- 有参数的宏成为宏函数
- 注意宏函数不会运算,而是就地展开,所以宏函数一般都是使用()来确保传入的表达式不会混乱,但是这也不是万能的。所以使用宏函数时候,确保调用时候传入的表达式对后续没有造成影响
- 宏函数的参数与返回值没有类型的要求
宏函数案例
#include <stdio.h>
#define MAX(a, b) (a) > (b) ? (a) : (b)
#define IS_HEX_CHARACTER(ch) \
((ch) >= '0' && (ch) <= '9') || \
((ch) >= 'A' && (ch) <= 'F') || \
((ch) >= 'a' && (ch) <= 'f')
int Max(int a, int b) {
return a > b ? a : b;
}
int main() {
int max = MAX(1.0, 3);
int max2 = MAX(1, MAX(3, 4));
//函数是会进行计算之后赋值,而宏函数是就地展开
int max3 = Max(1, Max(3, 4));
//这里传入的表达式就是对后续结果照成了影响
int max4 = MAX(max++, 5);
printf("max2: %d\n", max2);
printf("is A a hex character? %d\n", IS_HEX_CHARACTER('A'));
return 0;
}
四、条件编译
- ifndef:如果没有定义,用于判断一个宏是否被定义
- ifdef:如果定义,用于判断一个宏是否被定义
- if:如果,用于判断一个宏是否被定义或者判断一个表达式等等
- 对于if的例子有:#if define(MACRO) ==> #ifdef MACRO
- endif:结束
c++与c环境下代码编写
#ifdef __cplusplus
extern "C" {
#endif
//.....
#ifdef __cplusplus
};
#endif
判断当前c的版本
#if __STDC_VERSION__ >= 201112
puts("C11!!");
#elif __STDC_VERSION__ >= 199901
puts("C99!!");
#else
puts("maybe C90?");
#endif
还可以判断当前的操作系统等等…
五、自定义实现打印函数
#include <stdio.h>
#include <stdarg.h>
void Printlnf(const char *format, ...) {
va_list args;
va_start(args, format);
vprintf(format, args);
printf("\n");
va_end(args);
}
// "Hello ""world" ==> "Hello world"
// __FILE__
// __LINE__
// __FUNCTION__
// (../05.printlnf.c:20) main :
#define PRINTLNF(format, ...) printf("("__FILE__":%d) %s : "format"\n",__LINE__, __FUNCTION__, ##__VA_ARGS__)
#define PRINT_INT(value) PRINTLNF(#value": %d", value)
int main() {
int value = 2;
Printlnf("Hello World! %d", value);
PRINTLNF("Hello World! %d", value);
PRINTLNF("Hello World!");
PRINT_INT(value); // value: 2
int x = 3;
PRINT_INT(x);
PRINT_INT(3 + 4);
return 0;
}
六、乱七八糟
- 如果是Clion中想把头文件添加到工程中,在cmake.txt中写入include_direcories(“头文件所在的文件名字”)