新 C23 #embed 指令的目的是什么?

chq*_*lie 10 c language-lawyer c23

即将推出的 C23 标准中提供了新的预处理器指令:#embed

这是一个简单的例子:

// Placing a small image resource.

#include <stddef.h>

void show_icon(const unsigned char *, size_t);

int main (int, char*[]) {
    static const unsigned char icon_data[] = {
#embed "black_sheep.ico"
    };
    show_icon(icon_data, sizeof(icon_data));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是一个更详细的方法,从二进制数据初始化非数组(无论这意味着什么):

int main() {
    /* Braces may be kept or elided as per normal initialization rules */
    int i = {
#embed "i.dat"
    }; /* i value is [0, 2^(embed element width)) first entry */
    int i2 =
#embed "i.dat"
    ; /* valid if i.dat produces 1 value, i2 value is [0, 2^(embed element width)) */
    struct s {
        double a, b, c;
        struct { double e, f, g; };
        double h, i, j;
    };
    struct s x = {
        /* initializes each element in order according to 
           initialization rules with comma-separated list
           of integer constant expressions inside of braces
         */
#embed "s.dat"
   };
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

C语言中加入这个的目的是什么?

chq*_*lie 2

#embed允许轻松地将二进制数据作为数组unsigned char或其他类型包含在程序可执行映像中,而不需要从 Makefile 运行外部脚本。大多数编译器在解析此类数组时效率非常低,但有一个明显的例外:tcc

嵌入二进制甚至文本数据比从文件中读取数据有好处:

  • 可能没有文件系统
  • 文件的路径可能不明显
  • 文件可能丢失或无法访问

将其添加到 C 语言的主要原因似乎是一种新的冲动,即要将所有流行的 C++ 功能都转储到 C 上,徒劳地试图将 C 融合到两种语言的公共子集。C++ 委员会强烈支持这一扩展,而 C 委员会则不那么兴奋。

阅读详细信息: https://thephd.dev/_vendor/future_cxx/papers/C%20-%20embed.html

花了 30 年时间才strdup()将其纳入标准库,突然之间,C23 很高兴地将语言在各个方向上扩展了 50%,没有任何悔恨。

将其作为预处理器拼凑的理由非常值得怀疑,最后一个原因不言自明:

最后,Microsoft 存在一个 ABI 问题,即其最大字符串文字大小,无法使用字符串文字或任何类似字符串文字处理的内容来解决

该规范#embed充满了怪癖和缺点。不愿意编写正确的脚本会导致令人厌恶的情况,例如:

const unsigned char null_terminated_file_data[] = {
    #embed "might_be_empty.txt" \
        prefix(0xEF, 0xBB, 0xBF, ) /* UTF-8 BOM */ \
        suffix(,)
    0 // always null-terminated
};
Run Code Online (Sandbox Code Playgroud)

或者更糟:

int main () {
#define SOME_CONSTANT 0
    return
#embed </dev/urandom> if_empty(0) limit(SOME_CONSTANT)
    ;
}
Run Code Online (Sandbox Code Playgroud)

将二进制文件组装成可链接对象和资源的简单数据描述和操作语言的侵入性较小,并且易于包含在所有语言(更重要的是所有现有编译器)的现有构建系统中。

本文列举了一些有趣的例子,这些例子#embed可能会派上用场,但更通用的解决方案似乎是可能的。

  • 虽然我很欣赏您丰富的 C 经验,但我对这个答案投了反对票,因为其中大部分是您的个人观点,绝不反映 C 程序员之间的共识。我知道很多人不喜欢这种增长量,但我和许多像我一样对变化感到满意的人交谈过。我很高兴委员会正在标准化必须以较差或特定于实施的方式完成的事情。在“#embed”的情况下,这涉及编写特定于工具链的链接器命令,或将二进制文件转换为标头,并可能会缩短编译时间。 (12认同)
  • 在初始值设定项列表中间使用“#include”源文件的方式已经是有问题的。无论如何,如果没有咆哮,这将是一个更好的答案。我认为大多数人都同意 C 委员会应该专注于解决该语言的所有众所周知的问题,而不是引入新的、无用的功能。(例如,我对删除不是 2 的补码的所有内容表示赞赏,这将解决该语言的许多问题,并且可能是自删除隐式 int 以来 C 发生的最好的事情。) (6认同)
  • 是的,它是如此无用,以至于人们实际上向 ISO 发送蜗牛邮件信件,感谢该功能:https://thephd.dev/finally-embed-in-c23#actual-real-touchable-non-Electronic-mail (3认同)
  • 到目前为止,strdup 现在是 c 标准,而不仅仅是 posix。我的最爱之一 (2认同)