名稱空間
變體
操作

二進位制資源包含 (C23 起)

來自 cppreference.com

#embed 是一個預處理器指令,用於在構建中包含(二進位制)資源,其中資源被定義為可從翻譯環境訪問的資料來源。

目錄

[編輯] 語法

#embed < h-char-sequence > embed-parameter-sequence (可選) new-line (1)
#embed " q-char-sequence " embed-parameter-sequence (可選) new-line (2)
#embed pp-tokens new-line (3)
__has_embed ( " q-char-sequence " embed-parameter-sequence (可選) )
__has_embed ( < h-char-sequence > embed-parameter-sequence (可選) )
(4)
__has_embed ( string-literal pp-balanced-token-sequence (可選) )
__has_embed ( < h-pp-tokens > pp-balanced-token-sequence (可選) )
(5)
1) 搜尋由 h-char-sequence 唯一標識的資源,並將指令替換為對應於資源資料的逗號分隔整數列表。
2) 搜尋由 q-char-sequence 標識的資源,並將指令替換為對應於資源資料的整數列表。它可能會回退到 (1)
3) 如果 (1)(2) 都不匹配,pp-tokens 將進行宏替換。替換後的指令將再次嘗試與 (1)(2) 匹配。
4) 檢查資源是否可用於嵌入,是否為空,以及傳遞的引數是否受實現支援。
5) 如果 (4) 不匹配,h-pp-tokenspp-balanced-token-sequence 將進行宏替換。替換後的指令將再次嘗試與 (4) 匹配。
new-line - 換行符
h-char-sequence - 一個或多個 h-char 的序列,其中出現以下任何字元都會導致未定義行為
  • 字元 '
  • 字元 "
  • 字元 \
  • 字元序列 //
  • 字元序列 /*
h-char - 源字元集的任何成員,除了換行符和 >
q-char-sequence - 一個或多個 q-char 的序列,其中出現以下任何字元都會導致未定義行為
  • 字元 '
  • 字元 \
  • 字元序列 //
  • 字元序列 /*
q-char - 源字元集的任何成員,除了換行符和 "
pp-tokens - 一個或多個預處理標記的序列
string-literal - 一個字串字面量
h-pp-tokens - 一個或多個預處理標記的序列,除了 >
embed-parameter-sequence - 一個或多個 pp-parameter 的序列。請注意,與 attribute-list 不同,此序列不是逗號分隔的。
pp-parameter - 一個 attribute-token(參見:屬性),但由預處理標記而不是標記組成。
pp-balanced-token-sequence - 一個 balanced-token-sequence(參見:屬性),但由預處理標記而不是標記組成。

[編輯] 說明

1) 以實現定義的方式搜尋由 h-char-sequence 標識的資源。
2) 以實現定義的方式搜尋由 q-char-sequence 標識的資源。對於 (1,2),實現通常使用一種類似於但不完全相同的機制,即用於原始檔包含的實現定義的搜尋路徑。標準中的一個例子出現了結構 __has_embed(__FILE__ ...,這表明,至少在 (2) 的情況下,當前檔案所在的目錄應該被搜尋。
3) 指令中 embed 後的預處理標記像普通文字一樣處理(即,當前定義為宏名稱的每個識別符號都替換為其預處理標記的替換列表)。所有替換後的指令應匹配前兩種形式之一。將 <> 預處理標記對之間或一對 " 字元之間的預處理標記序列組合成單個頭名稱預處理標記的方法是實現定義的。
4) 搜尋由 h-char-sequenceq-char-sequence 標識的資源,就好像該預處理標記序列是語法 (3) 中的 pp-tokens 一樣,只是不再執行宏擴充套件。如果這樣的指令不滿足 #embed 指令的語法要求,則程式格式錯誤。如果資源搜尋成功,資源非空且所有引數都受支援,則 __has__embed 表示式評估為 __STDC_EMBED_FOUND__;如果資源為空且所有引數都受支援,則評估為 __STDC_EMBED_EMPTY__;如果搜尋失敗或傳遞的引數之一不受實現支援,則評估為 __STDC_EMBED_NOT_FOUND__
5) 只有當語法 (4) 不匹配時才考慮此形式,在這種情況下,預處理標記像普通文字一樣處理。

如果未找到資源或實現不支援其中一個引數,則程式格式錯誤。

__has_embed 可以在 #if#elif 的表示式中展開。它被 #ifdef#ifndef#elifdef#elifndefdefined 視為已定義的宏,但不能在其他任何地方使用。

資源具有一個*實現資源寬度*,即已定位資源的實現定義的位大小。其*資源寬度*是實現資源寬度,除非由 `limit` 引數修改。如果資源寬度為 0,則資源被視為空。*嵌入元素寬度*等於 CHAR_BIT,除非由實現定義的引數修改。資源寬度必須能被嵌入元素寬度整除。

#embed 指令的展開是一個由下面描述的整數常量表達式列表形成的標記序列。列表中每個整數常量表達式的標記組與列表中前一個整數常量表達式的標記組由逗號分隔。序列既不以逗號開頭也不以逗號結尾。如果整數常量表達式列表為空,則標記序列為空。指令被其展開,並在某些嵌入引數存在的情況下,附加或替換的標記序列所替換。

展開序列中整數常量表達式的值由資源資料的實現定義對映確定。每個整數常量表達式的值都在範圍 [02嵌入元素寬度) 內。如果

  1. 整數常量表達式列表用於初始化與 unsigned char 型別相容的陣列,或者如果 char 不能儲存負值,則與 char 相容的陣列,並且
  2. 嵌入元素寬度等於 CHAR_BIT

則陣列中已初始化元素的內容就好像資源二進位制資料在翻譯時被 fread 到陣列中一樣。

鼓勵實現考慮到翻譯時位序和位元組序以及執行時位序和位元組序,以更恰當地表示指令中的資源二進位制資料。這最大限度地增加了以下可能性:如果在翻譯時透過 #embed 指令引用的資源與透過執行時方式訪問的資源相同,那麼諸如 fread 或類似方式讀入連續儲存的資料將與從 #embed 指令的展開內容初始化的字元型別陣列進行逐位相等比較。

[編輯] 引數

標準定義了引數 limitprefixsuffixif_empty。指令中出現的任何其他引數必須是實現定義的,否則程式格式錯誤。實現定義的嵌入引數可能會改變指令的語義。

[編輯] limit

limit( constant-expression ) (1)
__limit__( constant-expression ) (2)

limit 嵌入引數在嵌入引數序列中最多出現一次。它必須有一個引數,該引數必須是一個整數(預處理器)常量表達式,求值為非負數且不包含標記 defined。資源寬度設定為整數常量表達式乘以嵌入元素寬度和實現資源寬度的最小值。

[編輯] suffix

suffix( pp-balanced-token-sequence (可選) ) (1)
__suffix__( pp-balanced-token-sequence (可選) ) (2)

suffix 嵌入引數在嵌入引數序列中最多出現一次。它必須有一個(可能為空的)預處理器引數子句。如果資源非空,引數子句的內容將緊隨指令的展開之後放置。否則,它沒有效果。

[編輯] prefix

prefix( pp-balanced-token-sequence (可選) ) (1)
__prefix__( pp-balanced-token-sequence (可選) ) (2)

prefix 嵌入引數在嵌入引數序列中最多出現一次。它必須有一個(可能為空的)預處理器引數子句。如果資源非空,引數子句的內容將緊隨指令的展開之前放置。否則,它沒有效果。

[編輯] if_empty

if_empty( pp-balanced-token-sequence (可選) ) (1)
__if_empty__( pp-balanced-token-sequence (可選) ) (2)

if_empty 嵌入引數在嵌入引數序列中最多出現一次。它必須有一個(可能為空的)預處理器引數子句。如果資源為空,引數子句的內容將替換指令。否則,它沒有效果。

[編輯] 示例

#include <stdint.h>
#include <stdio.h>
 
const uint8_t image_data[] = {
#embed "image.png"
};
 
const char message[] = {
#embed "message.txt" if_empty('M', 'i', 's', 's', 'i', 'n', 'g', '\n')
,'\0' // null terminator
};
 
void dump(const uint8_t arr[], size_t size)
{
    for (size_t i = 0; i != size; ++i)
        printf("%02X%c", arr[i], (i + 1) % 16 ? ' ' : '\n');
    puts("");
}
 
int main()
{
    puts("image_data[]:");
    dump(image_data, sizeof image_data);
    puts("message[]:");
    dump((const uint8_t*)message, sizeof message);
}

可能的輸出

image_data[]:
89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52
00 00 00 01 00 00 00 01 01 03 00 00 00 25 DB 56
...
message[]:
4D 69 73 73 69 6E 67 0A 00

[編輯] 參考

  • C23 標準 (ISO/IEC 9899:2024)
  • 6.4.7 標頭檔案名 (p: 69)
  • 6.10.1 條件包含 (p: 165-169)
  • 6.10.2 二進位制資源包含 (p: 170-177)

[編輯] 另請參閱

C++ 文件,關於 資源包含 (C++26 起)