cs107 编程范式(十一)

277 阅读2分钟

今天课程主要是了解一下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