预处理指令(五)
ISO/IEC 9899:2024标准提供了四个标准embed形参(standard embed parameter):limit、prefix、suffix、if_empty。
1、limit形参
limit形参表示计算资源宽度的预处理平衡标记序列。
(注:预处理平衡标记(preprocessing-balanced-token)中括号应严格配对,例如:(符号必须存在对应的)符号。预处理平衡标记应具有以下任一语法格式:( preprocessing-balanced-token-sequenceopt ),[ preprocessing-balanced-token-sequenceopt ],{ preprocessing-balanced-token-sequenceopt },除(、)、[、]、{、}外的任何预处理标记。)
在嵌入形参序列中limit形参可以出现0次或者1次;使用时应存在预处理器实参子句,预处理器实参子句应具有以下语法格式:
( constant-expression )
其中constant-expression是整数常量表达式,表示嵌入数据的最大字节数,其值应不小于0,并且在该表达式中不能出现defined标记。
#embed "test.bin" //合法。 #embed "test.bin" limit(4) //合法。 #define N 10 #embed "test.bin" limit(defined N) //非法。
无论先前是否进行过宏替换,常量表达式在预处理平衡标记序列处理后进行评估,预处理平衡标记序列的处理与常规文本一样遵循条件包含规则的规定,唯一例外是常量表达式中不允许存在defined宏表达式。
资源宽度应是以下三种情况之一:
-- 如果整数常量表达式评估为0,资源宽度为0。
#embed "test.bin" limit(0)
-- 如果实现资源宽度 < (嵌入元素宽度 × 整数常量表达式),资源宽度是实现资源宽度。
该规则可理解为请求包含的数据太大,超出了实现资源宽度,这种情况下资源宽度是实现资源宽度。
-- 如果实现资源宽度 ≥ (嵌入元素宽度 × 整数常量表达式),资源宽度等于(嵌入元素宽度 × 整数常量表达式)。
该规则可理解为请求包含的数据未超出实现资源宽度,这种情况下资源宽度等于(嵌入元素宽度 × 整数常量表达式)。
在字节宽度超大的特殊系统(例如:数字信号处理器,CHAR_BIT值会大于8。)中,基于标准8位字节假设的代码可能会低估数据需求,导致无法读取足够资源数据。
(注:ISO/IEC 9899:2024标准要求CHAR_BIT值大于等于8。)
//存在潜在的约束违规。 #embed "test_32_bits.bin" limit(1)
包含与某些实现交互的资源可能会接收到无限的数据流,如果不加以限制,可能会耗尽系统资源;使用limit形参可以只读取部分数据。
#embed "infinite_data.bin" limit(1024) //只读取1024个字节数据。
2、suffix形参
suffix形参表示在其预处理器实参子句中的预处理平衡标记序列会紧接在关联的#embed指令展开结果之后。
在嵌入形参序列中suffix形参可以出现0次或者1次;使用时应存在预处理器实参子句,预处理器实参子句应具有以下语法格式:
( pp-balanced-token-sequenceopt )
其中pp-balanced-token-sequence是预处理平衡标记序列。
假设文件test.bin内容为0X41,、0X42:
//#embed "test.bin"指令展开结果是:0X41, 0X42。 //数组arr1的初始化等价于 //const unsigned char arr1[] = { 0X41, 0X42 };。 const unsigned char arr1[] = { #embed "test.bin" }; //#embed "test.bin" suffix(, 0)指令展开结果是:0X41, 0X42,0。 //数组arr2的初始化等价于 //const unsigned char arr2[] = { 0X41, 0X42, 0 };。 const unsigned char arr2[] = { #embed "test.bin" suffix(, 0) };
如果#embed包含的资源为空,suffix形参会被忽略,不起任何作用。
//假设test.bin为空。 //suffix被忽略,初始化代码将扩展为 //const unsigned char arr[] = { };,这是空初始化,合法。 const unsigned char arr[] = { #embed "test.bin" suffix(, 0) };
3、prefix形参
prefix形参表示在其预处理器实参子句中的预处理平衡标记序列会置于关联的#embed指令展开结果(如果存在。)之前。
在嵌入形参序列中prefix形参可以出现0次或者1次;使用时应存在预处理器实参子句,预处理器实参子句应具有以下语法格式:
( pp-balanced-token-sequenceopt )
其中pp-balanced-token-sequence是预处理平衡标记序列。
假设文件test.bin内容为0X41,、0X42:
//#embed "test.bin"指令展开结果是:0X41, 0X42。 //数组arr1的初始化等价于 //const unsigned char arr1[] = { 0X41, 0X42 };。 const unsigned char arr1[] = { #embed "test.bin" }; //#embed "test.bin" prefix(0X23, )指令展开结果是:0X23, 0X41, 0X42。 //数组arr2的初始化等价于 //const unsigned char arr2[] = { 0X23, 0X41, 0X42 };。 const unsigned char arr2[] = { #embed "test.bin" prefix(0X23, ) };
如果#embed包含的资源为空,prefix形参会被忽略,不起任何作用。
//假设test.bin为空。 //prefix被忽略,初始化代码将扩展为 //const unsigned char arr[] = { };,这是空初始化,合法。 const unsigned char arr[] = { #embed "test.bin" prefix(0X23, ) };
4、if_empty形参
if_empty形参表示当#embed指令包含的资源为空时在其预处理器实参子句中的预处理平衡标记序列会替换#embed指令;如果#embed包含的资源不为空,if_empty形参会被忽略,不起任何作用。
在嵌入形参序列中if_empty形参可以出现0次或者1次;使用时应存在预处理器实参子句,预处理器实参子句应具有以下语法格式:
( pp-balanced-token-sequenceopt )
其中pp-balanced-token-sequence是预处理平衡标记序列。
资源为空存在两种情况:① 包含的资源本身为空;② 包含的资源本身不为空,但使用了limit(0)形参。
//假设test1.bin为空。 //数组arr1的初始化等价于 //const unsigned char arr1[] = { 0 };。 const unsigned char arr1[] = { #embed "test1.bin" if_empty(0) }; //假设test2.bin不为空。 //数组arr2的初始化等价于 //const unsigned char arr2[] = { 0 };。 const unsigned char arr2[] = { #embed "test2.bin" limit(0) if_empty(0) };
即使资源为空,如果搜索资源不成功,仍然违反约束。