C語言中#undef的語法定義是:#undef 標識符,用來將前面定義的宏標識符取消定義。
然而,在實際應用中,#undef到底可以用來做什麼?
整理了如下幾種#undef的常見用法。
1. 防止宏定義衝突
在一個程序塊中用完宏定義後,爲防止後面標識符衝突需要取消其宏定義。
例如:
#include <stdio.h>
int main()
{
#define MAX 200
printf("MAX = %d\n", MAX);
#undef MAX
int MAX = 10;
printf("MAX = %d\n", MAX);
return 0;
}
/******** 例程1:main.c ********/
2. 增強代碼可讀性
在同一個頭文件中定義結構類型相似的對象,根據宏定義不同獲取不同的對象,主要用於增強代碼的可讀性。
例如:在頭文件student.h中定義兩個學生對象(小明和小紅),兩個對象互不干涉。
#ifdef MING
#define MING_AGE 20
#define MING_HEIGHT 175
#endif
#ifdef HONG
#define HONG_AGE 19
#define HONG_HEIGHT 165
#endif
/******** 例程2:student.h ********/
在源文件中使用這兩個對象:
#include <stdio.h>
#define MING
#include "student.h"
#undef MING
#define HONG
#include "student.h"
#undef HONG
int main()
{
printf("Xiao Ming's age is %d.\n", MING_AGE);
printf("Xiao Hong's age is %d.\n", HONG_AGE);
return 0;
}
/******** 例程3:main.c ********/
在一個頭文件裏定義的兩個對象與分別在兩個頭文件裏定義效果相同,但如果將相似的對象只用一個頭文件申明,可以增強源代碼的可讀性。
3. 自定義接口
將某個庫函數包裝成自定義接口,而只允許用戶調用自定義接口,禁止直接調用庫函數。
(此例來源於《C和指針》)
例如,自定義安全的內存分配器接口:
/*
** 定義一個不易發生錯誤的內存分配器
*/
#include <stdlib.h>
#define malloc //防止直接調用malloc!
#define MALLOC(num, type) (type *)alloc((num) * sizeof(type))
extern void *alloc(size_t size);
/*********** 例程4:alloc.h ***********/
其中“#define malloc”是爲了防止用戶直接調用庫函數malloc,只要包含了這個頭文件alloc.h,就不能直接調用庫函數malloc,而只能調用自定義函數MALLOC,如果用戶要調用庫函數malloc編譯器會發生錯誤。
自定義安全的內存分配器的實現:
/*
** 不易發生錯誤的內存分配器的實現
*/
#include <stdio.h>
#include "alloc.h"
#undef malloc
void *alloc(size_t size)
{
void *new_mem;
new_mem = malloc(size);
if(new_mem == NULL)
{
printf("Out of memory!\n");
exit(1);
}
return new_mem;
}
/*********** 例程5:alloc.c ***********/
因爲在實現中需要用到庫函數malloc,所以需要用這一句“#undef malloc”取消alloc.h中對malloc的宏定義。
這種技巧還是比較有意思的,用於對已經存在的庫函數進行封裝。而且如果包含了自定義接口文件,就不能直接調用庫函數,而只能調用自定義封裝的函數。
4. 用於調試頭文件中
用於調試頭文件中,偶然看到這樣一個代碼用到了#undef,寫於此作爲記錄:
#ifdef _DEBUG_
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
/*********** 例程6:debug.h ***********/