问题描述
假设我有 2 个数据数组:
const uint8_t data1[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
const uint8_t data2[] = {0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
我希望能够单独读取这些数据,但也可以作为一个连续的数据块读取。
例如:我可以像访问 data[0] 一样访问 data1[8]。
原因:我在一些我不想接触的单个 .c 文件中有各种 const 数据定义(字体位图),但我想向它们附加一些额外的数据(额外的特殊字符)。所以我想
#include <original font file>
const uint8_t extrafonts[] = {<more font bitmaps>};
这能做到吗?
解决方法
在 C 中保证连续分配的唯一方法是使用数组数组。在这种情况下,const uint8_t [2][8]
似乎可以解决您的所有问题,因此请尽可能使用它。
否则,更高级的解决方案可以使用结构体和联合体。这些保证了分配顺序,但缺点是编译器可以在任何地方插入填充。在这种特定情况下,在任何真实世界的计算机上都不会出现问题,因为 8 字节的块是对齐的。如果你有一个标准的 C 编译器,你可以这样做:
#include <inttypes.h>
#include <stdio.h>
typedef union
{
struct
{
uint8_t data1 [8];
uint8_t data2 [8];
};
uint8_t data [16];
} data_t;
int main (void)
{
const data_t data =
{
.data1 = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07},.data2 = {0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f},};
for(size_t i=0; i<16; i++)
{
printf("%.2"PRIx8" ",data.data[i]);
}
}
现在您可以通过 data.data1
/data.data2
单独访问数组或使用 data.data
作为一个访问数组。
如果您担心结构体填充,则必须添加一些非标准的 #pragma pack(1)
或类似的特定于编译器的指令。
还有另一种可能适用于您的用例的替代方法:使用外部预处理。
使用您最喜欢的脚本语言和一些正则表达式魔术来读取原始字体源文件,并在数组末尾附加额外的字体数据。然后将其保存到新文件并在编译中使用它。
乍一看这似乎需要很多工作,但是由工具生成的 c 文件(我认为您的字体位图就是这种情况)往往具有可预测的格式,并且不太难解析。
,你可能会使用:
struct ArrayPair
{
uint8_t data1[8];
uint8_t data2[8];
};
const struct ArrayPair data =
{
{ 0x00,0x07 },{ 0x08,0x0f }
};
现在您可能可以使用:
data.data1[8]
它不是很优雅。你的要求不合理。
,您说这些是不同源文件上的 2 个全局数组。所以我忽略了您可以将这些与联合或结构分组的任何选项。
现在的坏消息是:绝对不能保证 2 个全局变量会按照标准 C 规则在内存中彼此相邻。
您可以这样做,但您需要改用编译器特定的扩展。您需要:
-
使用手动内存放置将变量彼此相邻放置。
-
禁用可能会破坏代码的任何优化或其他编译器功能,因为您正在访问数组越界。
请注意,我假设您处于资源有限的系统中,例如某些嵌入式系统。如果不是这种情况,那么只需创建第三个数组,并在程序启动时合并两个数组。