簡體   English   中英

從預處理器宏包含

[英]Include from preprocessor macro

我正在嘗試包含一個由預處理器宏構造的文件,但是由於有關令牌的規則,它似乎碰壁了。 我在這里將答案用作參考: C #include filename中的連接字符串 ,但我的情況有所不同,因為在用於構造include的定義中有小數點。 這是我目前無法通過預處理階段的內容:main.c:

#include <stdio.h>
#include <stdlib.h>

#define VERSION 1.1.0
#define STRINGIFY(arg) #arg
#define INCLUDE_HELPER(arg) STRINGIFY(other_ ##arg.h)
#define INCLUDE_THIS(arg) INCLUDE_HELPER(arg)

#include INCLUDE_THIS(VERSION)

int main(int argc, char **argv) {

   printf(INCLUDE_THIS(VERSION));
   fflush(stdout);
#if defined (SUCCESS)
   printf("\nSUCCESS!\n");
#endif
   return EXIT_SUCCESS;
}

other_1.1.0.h:

#define SUCCESS

如果我使用#define VERSION 1_1_0並相應地重命名了標頭,它將可以工作(但我無法使用,因為我無法控制實際項目使用的標頭文件的名稱),但是1.1.0不是有效的預處理程序令牌。

編輯:在進一步閱讀文檔后,我看到1.1.0是有效的preprocessing number 導致other_1.1.0串聯是無效的。 無論如何,仍然無法構建包含的問題。

經過一些試驗,我想出了一個雖然不理想但可行的解決方案。

#define VERSION _1.1.0
#define STRINGIFY(arg) #arg
#define INCLUDE_HELPER(arg) STRINGIFY(other ##arg.h)
#define INCLUDE_THIS(arg) INCLUDE_HELPER(arg)

#include INCLUDE_THIS(VERSION)

我不是將other_1.1.0粘貼在一起,而是將other_1.1.0粘貼。 我不確定為什么這是可以接受的,因為生成的令牌是相同的,但是確實存在。

我仍然希望有一個解決方案,允許我只定義版本號而不使用下划線,因此我將拒絕接受此答案,以防有人可以提出更優雅的解決方案(並為那些不願意這樣做的人使用)碰巧需要下划線)

一旦您停止考慮令牌串聯,這很容易。 字符串化可用於任何令牌序列,因此無需強制將其參數設為單個令牌。 您確實需要額外的間接調用,以便擴展參數,但這是正常的。

唯一的技巧是編寫不帶空格的序列,這就是ID的用途:

#define STRINGIFY(arg) STRINGIFY_(arg)
#define STRINGIFY_(arg) #arg
#define ID(x) x

#define VERSION 1.1.0
#include STRINGIFY(ID(other_)VERSION.h)

有關詳細說明,請參見https://stackoverflow.com/a/32077478/1566221

如果您將-DVERSION=1.1.0作為編譯行參數傳遞,而不是在源代碼中進行硬連接,那么沒有什么可以阻止您使用make或shell進行串聯的第二個定義了。 例如,在makefile中,您可能具有:

VERSION = 1.1.0
VERSION_HEADER = other_${VERSION}.h

CFLAGS += -DVERSION=${VERSION} -DVERSION_HEADER=${VERSION_HEADER}

接着:

#include <stdio.h>
#include <stdlib.h>

#define STRINGIFY(arg) #arg
#define INCLUDE_HELPER(arg) STRINGIFY(arg)
#define INCLUDE_THIS(arg) INCLUDE_HELPER(arg)

#include INCLUDE_THIS(VERSION_HEADER)

int main(void)
{
   printf("%s\n", INCLUDE_THIS(VERSION));
#if defined (SUCCESS)
   printf("SUCCESS!\n");
#endif
   return EXIT_SUCCESS;
}

這基本上是您的代碼,其中刪除了#define VERSION行,並使用了VERSION_HEADER的字符串化版本,而不是嘗試在源代碼中構造標頭名稱。 您可能要使用:

#ifndef VERSION
#define VERSION 1.1.0
#endif
#ifndef VERSION_HEADER
#define VERSION_HEADER other_1.1.0.h
#endif

對於某些合適的默認后備版本,以防運行編譯的人未在命令行上指定信息。 或者您可能使用#error You did not set -DVERSION=xyz on the command line而不是設置默認值。

編譯時(源文件hdr59.c ):

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -DVERSION=1.1.0 \
>     -DVERSION_HEADER=other_1.1.0.h hdr59.c -o hdr59
$ ./hdr59
1.1.0
SUCCESS!
$

我會將宏的三行和#include行放入單獨的小標題中,以便在需要版本標題時可以將其包含在內。 如果也需要默認設置,則將代碼放入單獨的標頭以供重用的重要性增加了。 該程序的源代碼可能包含:

#include "other_version.h"

並且該標頭將安排或多或少地包含正確的文件,如圖所示。

暫無
暫無

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

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