今天课程主要是了解一下c的预处理相关知识点。
#define
#define kWidth 40
#define kHeight 80
#define kParameter 2*(kWidth+kHeight)
上述语句其实不用做过多的解释, 了解c语言的同学应该都明白, #define主要是用于替换操作。同时也可以像函数那样将参数传递给#define, 这种形式被称作宏。
#define MAX(a,b) ((a) > (b) ? (a) : (b))
相比于函数, 宏在使用的过程会省略掉函数的参数传递、返回等操作的开销, 因此宏操作更加快速并且高效。
MAX(40.2, "Hello");
对于上述操作来说, 在预处理阶段是不会报错的, 报错是在编译阶段发生的。
#define NthElemAddr(base, elemSize, index) \
((char*)base + index * elemSize)
对于上述类似代码可以使用宏定义或者函数的形式来进行处理, 但是请注意确保宏定义是正确的, 因为宏定义很容易会出现错误。
接下来, 来看一下assert的宏定义。
#ifdef NDEBUG
#define assert(cond) (void)0
#else
#define assert(cond) \
(cond) ? ((void)0) : fprintf(stderr, "行号等信息"), exit(0)
#endif
(void)0语句类似一个占位符, 在进行编译时, 不会产生任何一句汇编代码。
现在, 我们来看看宏定义容易出现的问题。
int max = MAX(fib(100), fact(400)); // int max = ((fib(100)) > (fact(400)) ? (fib(100)) : (fact(400)))
对于这句代码来说, 在执行时会产生重复的函数调用, 增加一定的性能开销。
int larger = MAX(m++, n++) \\ int larger = ((m++) > (n++) ? (m++) : (n++))
而对于这句代码来说, 就会产生错误, 因为变量会多加一次。
#include
// 对于这类头文件, 表示根据编译器提供的默认路径去查找
#include <stdio.h>
#include <assert.h>
// 对于这类头文件, 表示从当前目录开始查找
#include "vector.h>
#include操作是递归深度搜索, 如果出现了循环包含的情况, 就会发生无限递归。
一种标准的解决方案如下所示:
#ifndef _vector_h_
#define _vector_h_
...
#endif