【问题标题】:Is there a limit to the length of a macro's contents?宏内容的长度是否有限制?
【发布时间】:2018-12-30 10:30:25
【问题描述】:

对于嵌入式程序,我经常将数据表转换为标头#defines,然后将其放入 .c 程序中的变量/数组中。

我刚刚编写了一个转换工具,它可能会以这种格式产生大量输出,现在我想知道我是否应该意识到这种模式的任何限制。

标题示例:

#define BIG_IMAGE_BLOCK      \
    0x00, 0x01, 0x02, 0x03,  \
    0x04, 0x05, 0x06, 0x07,  \
    /* this goes on ... */   \
    0xa8, 0xa9, 0xaa, 0xab

代码示例(avr-gcc):

const uint8_t ImageData[] PROGMEM = {
    BIG_IMAGE_BLOCK
};

似乎无法找到这个特定问题的答案,似乎被所有询问标识符、行长和宏重新评估限制的人淹没了。

【问题讨论】:

  • C99 5.2.4.1: 4095 个字符在一个逻辑行 [或更多]。
  • 如果您使用的是 Gnu 工具集,将二进制文件直接写入文件可能会更容易,然后使用 objcopy 将其转换为 ELF 对象。

标签: c macros preprocessor


【解决方案1】:

C17 第 5.2.4.1 节第 1 节列出了一些最低翻译限制。这意味着允许但不要求实现超出这些限制。在下面的引文中,我省略了对脚注的一些引用,并突出显示了最可能与此问题相关的一个。

实现应该能够翻译和执行至少一个包含至少 以下每一项限制的一个实例:

— 127 个嵌套级别的块

— 63 个嵌套级别的条件包含

— 12 个指针、数组和函数声明符(任意组合)修改算术, 结构、联合或 空白 输入声明

——一个完整的声明符内有 63 层括号内的声明符

——一个完整的表达式中有 63 个嵌套级别的括号表达式

— 内部标识符或宏名称中的 63 个有效初始字符(每个通用字符名称或扩展源字符都被视为单个字符)

— 外部标识符中的 31 个有效初始字符(每个指定短标识符为 0000FFFF 或更少的通用字符名称被视为 6 个字符,每个指定短标识符为 00010000 或更大的通用字符名称被视为 10 个字符,每个扩展源字符被视为与相应的通用字符名称相同的字符数(如果有)

——一个翻译单元中有 4095 个外部标识符

— 511 个标识符,在一个块中声明了块范围

——在一个预处理翻译单元中同时定义4095个宏标识符

——一个函数定义中有 127 个参数

——一个函数调用中有 127 个参数

——一个宏定义127个参数

— 一次宏调用中有 127 个参数

逻辑源代码行中有 4095 个字符

— 字符串文字中的 4095 个字符(连接后)

— 对象中的 65535 字节(仅在托管环境中)

—#included 文件的 15 个嵌套级别

——一个开关的 1023 个 case 标签 语句(不包括任何嵌套的 转变 声明)

— 单个结构或联合中的 1023 个成员

— 单个枚举中的 1023 个枚举常量

— 单个 struct-declaration-list 中的 63 级嵌套结构或联合定义

逻辑源代码行中字符数的相关性是因为宏的扩展将成为单个逻辑源代码行。例如,如果在宏定义中使用\ 表示多行宏,则所有部分都拼接成一个源代码行。这是第 5.1.1.2 节第 1 条第二项的要求。

根据宏的定义方式,它也可能受到其他限制的影响。

实际上,所有实现(编译器及其预处理器)都超出了这些限制。例如,gnu 编译器允许的逻辑源代码行长度由可用内存决定。

【讨论】:

    【解决方案2】:

    C 标准对指定此类限制非常宽松。 C 实现必须能够翻译逻辑源代码行上包含 4095 个字符的“至少一个程序”(C 2018 5.2.4.1)。但是,在其他行较短的情况下,它可能会失败。宏替换文本的长度(以字符或预处理器标记衡量)未明确解决。

    因此,C 实现可能对宏替换文本和其他文本的长度有限制,但它不受 C 标准控制,而且 C 实现通常没有很好地记录或根本没有记录。

    准备源代码所需的复杂或海量数据的常用技术是编写一个单独的程序,在编译时执行以处理数据并编写所需的源文本。这通常比滥用 C 预处理器功能更可取。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-04
      • 1970-01-01
      • 1970-01-01
      • 2010-09-20
      • 1970-01-01
      • 1970-01-01
      • 2020-05-20
      相关资源
      最近更新 更多