一、入題
在頭文件的書寫中,都加入了如下內容:
#ifndef __頭文件名_H #define __頭文件名_H #endif
曾經在書中看到的解釋是“防止重復定義”,今天突然想到為什么是這樣的解釋。
二、測試
測試文件共三個,兩個頭文件:head1.h、head2.h,一個C源程序:program.c。
1、頭文件沒有宏定義的代碼實驗
① 測試代碼
head1.h
unsigned char global[] = "hello world!";
head2.h
unsigned char global[] = "hello world!";
program.c
#include "head1.h" #include "head2.h" #include <stdio.h> int main(void) { printf("%s\n",global); return 0; }
② 測試結果
程序在編譯時提示:“重復定義了全局變量global”。
2、頭文件含有宏定義的代碼實驗
① 測試代碼
head1.h內容:
#ifndef __HEAD_H #define __HEAD_H unsigned char global[] = "hello world!"; #endif
head2.h
#ifndef __HEAD_H #define __HEAD_H unsigned char global[] = "hello world!"; #endif
program.c
#include "head1.h" #include "head2.h" #include <stdio.h> int main(void) { printf("%s\n",global); return 0; }
② 測試結果
程序正常編譯、連接,生成可執行文件。
三、原因分析
1、頭文件沒有宏定義的代碼實驗
program.c的預編譯結果:
head1.h被替換為:
unsigned char global[] = "hello world!";
head2.h被替換為:
unsigned char global[] = "hello world!"; #include <stdio.h> int main(void) { printf("%s\n",global); return 0; }
顯然,重復定義了global。
2、頭文件含有宏定義的代碼實驗
program.c的預編譯結果:
1 head1.h被替換為: 2 #ifndef __HEAD_H 3 #define __HEAD_H 4 5 unsigned char global[] = "hello world!"; 6 #endif 7 8 9 head2.h被替換為: 10 #ifndef __HEAD_H 11 #define __HEAD_H 12 13 unsigned char global[] = "hello world!"; 14 #endif 15 16 #include <stdio.h> 17 18 int main(void) 19 { 20 printf("%s\n",global); 21 return 0; 22 }
由於一開始沒有定義宏__HEAD_H,所以在2行的時候編譯器判斷為真,就定義了宏__HEAD_H和全局變量global。
由於在3行的時候定義了宏__HEAD_H,所以編譯器判斷10行的條件為假,自然也會將其中的內容忽略掉。結果就是:兩個頭文件實際上只定義一次宏__HEAD_H和全局變量global,所以編譯的時候能正常通過。
三、實際應用中
比如STM32單片機編程的時候,main.c包含了兩個外設頭文件stm32f10x_gpio.h、stm32f10x_i2c.h,而這兩個頭文件又都包含了stm32f10x.h。在main.c的預編譯過程中,顯然stm32f10x.h要被包含兩次。通過“頭文件的宏定義#ifndef”就可以解決重復包含引起的重復定義的問題。