簡體   English   中英

使用宏定義包含文件

[英]Using a macro to define an include file

長話短說,我正在編寫一些代碼,這些代碼需要基於各種配置選項的不同頭文件。 我可以做這樣的事情:

#if OPTION == A
#include "relative/path/to/file/a.hpp"
#elseif OPTION == B
#include "relative/path/to/file/b.hpp"
#elseif OPTION = ...
...
#endif

這會起作用,但對於可能不僅僅是少數文件的情況,這似乎是一個非常丑陋的解決方案。 我也可以簡單地包含所有各種頭文件,但這似乎也有點丑陋的解決方案,如果文件(出於某種可怕的原因)開始重新定義相同的對象,它可能會在未來造成問題。 我的想法是,像下面這樣的東西會很好,特別是在其余代碼是如何編寫的上下文中:

#define QUOTE(str) #str
#define STRINGIFY(A,B) QUOTE(A##B)
...
#include STRINGIFY(relative/path/to/option/,OPTION)

這個問題似乎有兩個方面:

  1. OPTION定義沒有在STRINGIFY內正確展開。
  2. 如果路徑名中有任何正斜杠,則STRINGIFY完全失敗,g++ 給我一個錯誤,如下所示:

錯誤:粘貼“/”和“OPTION”沒有給出有效的預處理令牌

我似乎找不到任何關於為什么/是 C++ 預處理器的壞字符的真實信息,只有幾篇文章說你應該把"/"放入並依賴自動 C++ 字符串連接(這在#include語句)。 如果我只是想做一些非常愚蠢的事情,我願意考慮設計替代方案,但我也想弄清楚為什么這不起作用。

編輯:我應該澄清一下,我正在研究最初由一組科學家設計的代碼庫。 合理的編碼約定和對如何使用代碼的典型期望完全被排除在外。 這段代碼可能至少會被修改多次,通常由那些將整個職業生涯都用於編寫 Fortran 77 並認為面向對象編程是一些新奇的發明,只會讓你的代碼更難理解的人修改。

編寫宏時,必須查看預處理后的輸出。 使用gcc就是-E選項。

要包含不同的文件,我將依賴您的構建工具而不是宏 voodoo。 例如,當代碼是

include option

然后gcc -E -option=\"foo.h\"產生

include "foo.h"

請注意,我在這里省略了# ,否則由於找不到"foo.h" ,預處理會失敗。

我想做類似的事情,四處搜索並找到了這篇文章,在嘗試了一些事情之后,我想我可以幫助你。

所以,你的方法:

#define QUOTE(str) #str
#define STRINGIFY(A,B) QUOTE(A##B)
...
#include STRINGIFY(relative/path/to/option/,OPTION)

據我了解https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html不起作用,因為使用##粘貼令牌時,結果必須是有效令牌,其中類似於path/to/file.hpp不是有效的預處理令牌。

現在,我認為您只需要一個包含路徑和要替換的令牌的宏。 好吧,如果您使用-I標志,您實際上並不需要添加相對路徑。 您的宏可能看起來像#define myMacro relative/path/to/file/OPTION.hpp ,然后您只需要定義OPTION並將其傳遞給一個宏,以便OPTION被其值替換,然后另一個宏被字符串化。 此處描述了這兩個級別的宏https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing

以下示例將說明這兩種情況(帶/不帶-I標志)。

考慮這個目錄結構:

.   
|-- a.c 
|-- headers
|   |-- A.hpp
|   `-- B.hpp
`-- makefile

其中交流:

#define header OPTION.hpp
#define xstr(x) #x
#define str(x) xstr(x)
#include str(header)

生成文件:

PATH_OPTION ?= headers/A
OPTION ?= A

.PHONY: all 
all: a.c 
        cpp -D OPTION=${PATH_OPTION} $<
        cpp -I./headers -D OPTION=${OPTION} $<

A.hpp

#warning Including A.hpp
1   

B.hpp

#warning Including B.hpp
2   

有了這個,您可以調用make默認情況下將包含headers/A.hpp並且您應該能夠看到兩種方法(帶/不帶-I標志)工作並打印到標准輸出相應的警告。

要包含headers/B.hpp ,您可以根據您采用的方法make OPTION=Bmake PATH_OPTION=headers/B

我也嘗試使用g++而不是cpp ,它也可以。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM