很抱歉,您提供的信息不完整,无法确定您想要表达的具体内容。如果您能提供更多的上下文或者详细信息,我会尽力帮助您解答。例如,您是想询问C23和C26在某个特定领域(如化学、数学、编程等)中的含义,还是其他方面的信息?请提供更多信息,以便我能够给出准确的回答。
摘要:c++26最近刚敲定标准,新增了许多重量级特性。 不过目前能实际上手测试的特性不多,毕竟标准刚刚确定,比较大的变更里只有“资源嵌入”或者用标准文档里英文名“resource inclusion”这个新特性
c++26最近刚敲定标准,新增了许多重量级特性。
不过目前能实际上手测试的特性不多,毕竟标准刚刚确定,比较大的变更里只有“资源嵌入”或者用标准文档里英文名“resource inclusion”这个新特性可以尝鲜。
虽然这篇文章标题叫指南,但实际上更像实验记录,而且现在属于早期阶段编译器对资源嵌入的处理有可能会有改变(不过语法不会改了),所以把这篇文章当教程看也行但得注意文章内容与实际使用上可能存在差别。
测试环境:
操作系统:macOS 15 和 Fedora 42
编译器:GCC 15.1
测试文本数据编码:UTF-8
网站上显示GCC15是完全支持#embed资源嵌入的,本来还想测试一下clang20,遗憾的是gcc测下来还有点小bug,况且clang在网站上显示只支持部分embed功能,因此我就不蹚雷了。
准备好环境之后我们来了解一下基础语法。
为什么需要embed
把数据嵌入到代码里有不少好处,比如:
部署更简单,不需要额外捆绑资源文件
程序可以更健壮,无需额外处理资源文件缺失或数据读取失败等意外情况
能避免一些权限问题,一些系统上对文件的存放和读写有比较严格的限制
市面上也有很多工具可以完成资源/数据的嵌入,有些工具还提供灵活的数据查找功能,比如Qt的rcc。但这些工具一直有如下几个缺点:
需要安装额外工具。这会增加项目的复杂性和管理成本,比如如何在CI里使用这些工具
显著增加代码体积。众所周知二进制数据很难直接原样放进文本格式的代码里,所以要么对数据序列化要么对数据进行编码(比如base64),不管那种都会让二进制数据体积膨胀
学习成本高。市面上的工具用法看似类似,实则差异明显,导致工具A的经验在工具B或C中难以通用
因此我们需要一种易学、通用、无需额外编解码或序列化即可嵌入二进制数据的方案。于是#embed就诞生了。
在正式进入C++26的embed提案里有一组性能对比测试,我们只看GCC相关的:
执行速度:
Strategy
40 KB
400 KB
4 MB
40 MB
#embed GCC
0.236 s
0.231 s
0.300 s
1.069 s
xxd-generated GCC
0.406 s
2.135 s
23.567 s
225.290 s
内存占用:
Strategy
40 KB
400 KB
4 MB
40 MB
#embed GCC
17.26 MB
17.96 MB
53.42 MB
341.72 MB
xxd-generated GCC
24.85 MB
134.34 MB
1,347.00 MB
12,622.00 MB
看着相当不错。美中不足的是缺少可执行文件体积对比,这个在我们学完了embed的用法之后可以额外做个测试。
基础语法
这次没有基础回顾环节,因为是全新的语法,直接学就完事了。
c和c++的embed语法形式差不多,所以放一起讲了。顺便我也不做标准文档的复读机,否则仅解释一个pp-token(预处理器可以接受的token)就可能占用大量篇幅,我会用简单的语言配上简单的例子做解释。
embed指令是预处理器的一种,语法如下:
# embed <header-name>|"header-name" parameters... new-line
#embed是指令名部分,这个很容易理解。
<header-name>|"header-name"是要嵌入的资源文件的名字,正如其中“header name”所暗示的,嵌入的资源文件搜索路径和头文件一样,引号代表优先搜索当前目录之后搜索编译器的头文件目录;尖括号则表示只搜索编译器限定的头文件存放目录。嵌入资源文件还可以使用绝对路径,比如#embed "/dev/urandom",注意要用引号。所以最基础的嵌入资源的语法是这样的:
#embed <my-data> // linux GCC 会去/usr/include和通过-I参数传给编译器的目录下查找有没有一个叫 my-data 的文件
#embed "data1.bin" // 先在源文件所在的当前目录下寻找 data1.bin,找不到则去编译器的搜索路径里查找
parameters...是一组形式类似选项A 选项B或者选项A(参数1) 选项B(参数1, 参数2, ...)的东西,学名叫embed-parameter,中译名还没有,暂且就叫嵌入参数好了。嵌入参数主要用于给嵌入的资源做一些限制或者添加某些属性,后面会单独开一节内容细讲。嵌入参数也可以有自己的参数,这些参数必须是编译期常量。
