是否可以用结构初始化uint8_t数组?
我想要达到的目标类似于:
#define BIGGER_THAN_STRUCT 1024
struct Device {
uint32_t address;
uint32_t id;
};
const uint8_t bytes[BIGGER_THAN_STRUCT] = (struct Device) {
.address = 123,
.id = 456,
};
我想这样做的原因是为了获得我写入字节数组的内容的简单叠加视图。我只想要一个简单的接口,以便我可以获得结构显示的信息所需的第一个字节。
如果那不可能,最接近它的是什么?
答案 0 :(得分:3)
C中覆盖数据类型的标准方法是使用联合:
#include <stdio.h>
#include <stdint.h>
#define BIGGER_THAN_STRUCT 1024
struct Device {
uint32_t address;
uint32_t id;
};
union Memory {
uint8_t bytes[BIGGER_THAN_STRUCT];
struct Device devices[BIGGER_THAN_STRUCT/sizeof(struct Device)];
};
const union Memory memory = {
.devices = {
{ .address = 123, .id = 30 },
{ .address = 111, .id = 89 }
}
};
int main(void)
{
unsigned i;
for (i = 0; i < 16; i++)
printf("%d ", memory.bytes[i]);
putchar('\n');
return 0;
}
,
$ ./a
123 0 0 0 30 0 0 0 111 0 0 0 89 0 0 0
答案 1 :(得分:1)
除了通过union
(由 hdante 此处https://stackoverflow.com/a/27462808/694576提出)而不是尝试:
const uint8_t bytes[BIGGER_THAN_STRUCT] = (struct Device) {
.address = 123,
.id = 456,
};
快速而肮脏:
uint8_t bytes[BIGGER_THAN_STRUCT] = {0};
*((struct Device *) bytes) = ((struct Device) {
.address = 123,
.id = 456,
});
或更好的做法:
struct Device dev = {
.address = 123,
.id = 456,
};
uint8_t bytes[BIGGER_THAN_STRUCT] = {0};
...
size_t size_dev = sizeof dev;
memcpy(bytes, &dev, size_dev);
然后检查数组bytes
直到size_dev - 1
元素。
答案 2 :(得分:0)
这样就可以了
static const uint8_t buffer[BIGGER_THAN_STRUCT] = {
0x7b, 0x00, 0x00, 0x00,
0xc8, 0x01, 0x00, 0x00
};
答案 3 :(得分:0)
通常,当我必须使用结构化字节包时,我创建了一个“视图”结构/类,它为我提供了一个内存块的更高级别接口。手动指针算术通常太容易重复。创建一个“内存视图”结构并对其进行单元测试。
struct memory_view {
uint32_t *addr;
uint32_t *id;
};
void view_init(struct memory_view *view, void *buf, size_t bufsz) {
// TODO: validate buffer size using bufsz here
view->addr = (uint32_t*)buf;
view->id = (uint32_t*)(buf + sizeof(uint32_t));
}
struct memory_view view;
uint8_t buffer[LARGE_NUMBER];
view_init(&view, buffer, LARGE_NUMBER);
*view->addr = 0xDEADBEEF;
*view->id = 0xCAFEBABE;
当初始化结构以访问位于某个存储区域中的不同硬件寄存器时,您可以在设备驱动程序中看到类似的技术。
您还可以获取缓冲区指针,将其强制转换为结构并尝试使用此内存块,因为它是一个结构。可行,但内存对齐会让你很难受。此类代码可能有效,也可能无效,具体取决于编译器和系统架构。
答案 4 :(得分:0)
我认为您可能想要做类似的事情,即使副本不是必需的,因为b_sample
正是您所需要的。
#include <stdio.h>
#include <stdint.h>
typedef struct Device dev;
struct Device {
uint32_t address;
uint32_t id;
};
int main(void) {
//create an instance `sample.address=123` and `sample.id=456`
dev sample = (dev) { 123, 456 };
//convert dev pointer to byte pointer, so you loop through bytes
uint8_t* b_sample = (uint8_t *)(&sample);
//buffer for copy
uint8_t* bytes[1024];
int size = (int)(sizeof(dev)/sizeof(uint8_t)), i;
for(i = 0; i < size; i++) {
bytes[i] = b_sample[i];
//see what values you copy
printf("%x ", bytes[i]);
}
return 0;
}
演示:http://codepad.org/wE8dbBV1
如果您想将结构划分为uint16_t
段,则可以安全地将所有uint8_t
替换为uint16_t
答案 5 :(得分:0)
可以使用uint8_t byte[]
数组。您还可以为每个bitfield
和addr
使用id
的结构。您(可能/可能不)发现它更方便,但它确实提供了一种简单的方法来保持与任何给定addr/id
对相关联的偏移信息。
我不相信有一种方法可以直接使用结构类型指定的初始化程序来填充uint8_t byte
数组。我认为最接近的完全初始化将是memcpy
。我在下面的示例中包含了这一点。 注意,没有什么可以阻止您使用uint8_t byte
填充memcpy
数组,但是您必须跟踪offset
中的uint8_t byte
数组准确地指向任何给定元素的addr
或id
中的任何给定字节。这是bitfield使事情变得更容易的地方。您会在struct Device
索引和uibitfield
索引之间获得一对一关联,其中a1..4
和b1..4
是每个addr
内的字节分别为{1}}和id
。
使用uint8_t
数组的版本显示在此版本下方。
这是一个简短的示例,其中包含struct Device
:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef struct /* bitfield corresponding to struct Device */
{
unsigned int a1 : 8,
a2 : 8,
a3 : 8,
a4 : 8;
unsigned int b1 : 8,
b2 : 8,
b3 : 8,
b4 : 8;
} uibitfield;
struct Device { /* original struct Device */
uint32_t addr;
uint32_t id;
};
int main () {
/* test data in an array of struct Device */
struct Device dev[] = { {0x4009f0, 0}, {0x4009f1, 1}, {0x4009f2, 2}, {0x4009f3, 3},
{0x4009f4, 4}, {0x4009f5, 5}, {0x4009f6, 6}, {0x4009f7, 7},
{0x4009f8, 8}, {0x4009f9, 9}, {0x4009fa, 10}, {0x4009fb, 11},
{0x4009fc, 12}, {0x4009fd, 13}, {0x4009fe, 14}, {0x4009ff, 15},
{0x400a00, 16}, {0x400a01, 17}, {0x400a02, 18}, {0x400a03, 19} };
int it = 0; /* general iterator */
size_t sz = sizeof (dev)/sizeof (*dev); /* size of array */
/* create validate and fill bitfield array */
uibitfield *bytes = calloc (sz, sizeof (*bytes));
if (!bytes) {
fprintf (stderr, "error: allocation failed.\n");
return 1;
}
memcpy (bytes, dev, sz * sizeof (dev));
/* print bytes in each addr & id in dev */
for (it = 0; it < sz; it++)
printf ("\n addr[%2d]: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n id[%2d]: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
it, (bytes + it)->a1, (bytes + it)->a2, (bytes + it)->a3, (bytes + it)->a4,
it, (bytes + it)->b1, (bytes + it)->b2, (bytes + it)->b3, (bytes + it)->b4);
printf ("\n");
return 0;
}
<强>输出:强>
$ ./bin/memview
addr[ 0]: 0xf0, 0x09, 0x40, 0x00
id[ 0]: 0x00, 0x00, 0x00, 0x00
addr[ 1]: 0xf1, 0x09, 0x40, 0x00
id[ 1]: 0x01, 0x00, 0x00, 0x00
addr[ 2]: 0xf2, 0x09, 0x40, 0x00
id[ 2]: 0x02, 0x00, 0x00, 0x00
addr[ 3]: 0xf3, 0x09, 0x40, 0x00
id[ 3]: 0x03, 0x00, 0x00, 0x00
addr[ 4]: 0xf4, 0x09, 0x40, 0x00
id[ 4]: 0x04, 0x00, 0x00, 0x00
(snip)
注意:目前还不清楚你将如何使用/填充struct Device
以及你想要对stuct Device
中的数据进行多少初看,所以这是仅作为查看数据的示例。
使用uint8_t字节数组:
如果你想使用`uint8_t数组,那么所需的更改是最小的:
/* using a uint8_t byte array */
uint8_t *bytearr = calloc (sz * 4, sizeof (*bytearr));
if (!bytearr) {
fprintf (stderr, "error: allocation failed.\n");
return 1;
}
memcpy (bytearr, dev, sz * sizeof (dev));
/* print bytes in each addr & id in dev using uint8_t array */
for (it = 0; it < sz * 4; it+=8)
printf ("\n addr[%2d]: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n id[%2d]: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
it, bytearr[it], bytearr[it+1], bytearr[it+2], bytearr[it+3],
it, bytearr[it+4], bytearr[it+5], bytearr[it+6], bytearr[it+7]);
输出相同
答案 6 :(得分:0)
这是:
#define BIGGER_THAN_STRUCT 1024
struct Device {
uint32_t address;
uint32_t id;
};
struct DeviceAndData {
struct Device d;
char filler[BIGGER_THAN_STRUCT - sizeof(Device)];
};
const struct DeviceAndData bytes_pre = { .d = { .address = 123, .id = 456 } };
const uint8_t* bytes = (uint8_t*)&bytes_pre;
诀窍? :)