在两个字节上写入 uint8 变量?

Writing a uint8 variable on two bytes?

提问人:Ciuboss 提问时间:11/13/2023 更新时间:11/13/2023 访问量:104

问:

所以有点奇怪,因为我正在使用一个我无权访问的界面。但它的要点是这样的:我有一个 16 字节、16 个 uint8 元素的数组。前 12 个元素非常具体,这意味着对于 array[0] 和数组1,我个人给出了具体的值,而接下来的 10 个元素,我需要复制另一个数组的元素。我遇到的问题是数组的最后 4 个元素,基本上是最后 4 个字节。在我的“图表”中,我有这样的东西:enter image description here

如图所示,它说 index 和 ID 不像具有 2 个 uint8 元素的数组,它们看起来像是一个变量,每个变量占用 2 个字节。然而,问题在于,为了获取 index 和 ID 的值,我使用了我之前讨论过的接口,并且该接口接受 uint8* 值。所以我不确定我应该做什么。 我是否应该声明 uint8 类型的索引和 ID 并将它们传递到这个函数中,它们将获得某个值,然后使用按位运算符将其放在 2 个字节上?我的代码实现如下所示:

uint8 FinalArray[16];
uint8 index;
uint8 ID;
uint8 buffer[10];

FinalArray[1] = 0x01;
FinalArray[2] = 0x10;
//I do some data manipulation for buffer here, does not matter
memcpy(&FinalArray[2], buffer, sizeof(buffer));

//and here I am unsure of how I should proceed
Get_IndexAndID(&index, &ID);
//the function returns just 1 or 0 in case it was successful or not, so I guess I need to pass the variables by reference for them to change value inside the function itself
//I also got a hint that inside this function, both index and ID get values because they are the "destination" inside a memcpy function, but I am not sure if this changes the way they are passed or what

//is this even doing what I am thinking of?
FinalArray[12] = index & 0xFF;
FinalArray[13] = (index >> 8) & 0xFF;
FinalArray[14] = ID & 0xFF;
FinalArray[15] = (ID >> 8) & 0xFF;

Any help, additions or corrections to my code would be really welcome. Thanks!
C 嵌入式 按位运算符

评论

2赞 greg spears 11/13/2023
是的,如果它的字节序成功,那么你使用 & 运算符的按位工作看起来是正确的。另一种可以说是更简单的方法是将数组转换为 16bit int 类型,然后将数组的最后两个 int(偏移量 6 和 7)分配给变量 16bit int。如果我不清楚,我很乐意发布代码。
1赞 Ciuboss 11/13/2023
@gregspears 呵呵,我很抱歉,我不是100%确定你的意思。我最近刚刚切换到嵌入式类型项目,使用按位运算符是我目前的新挑战。只是你说我对代码的最后部分所做的是可以的,这让我很开心,哈哈。
1赞 greg spears 11/13/2023
@Ciuboss -- 很高兴听到这个消息。这是另一种方式我在描述——干杯!
1赞 Ciuboss 11/13/2023
@gregspears 哦,该死的,这很有趣,我从来没有见过这样做。我将查看您的解决方案,以更多地了解某些方面。多谢!
3赞 0___________ 11/13/2023
@gregspears,它是指针双关语,并且由于违反了严格的别名规则,因此会调用未定义的行为。不要建议人们这样做。这是不正确的。

答:

1赞 Craig Estey 11/13/2023 #1

根据您的图表,它可以是:struct

struct diagram {
    uint8 v01;
    uint8 v10;
    uint8 buffer[10];
    uint16 index;
    uint16 ID;
};

union bigbuf {
    uint8 array[16];
    struct diagram diagram;
};

根据您用于放入 (即 )的代码,它们每个为 16 位。所以,他们应该是而不是indexIDFinalArray<<uint16 uint8


C 数组是“原点 0”而不是“原点 1”。所以,而不是:

FinalArray[1] = 0x01;
FinalArray[2] = 0x10;

你想要:

FinalArray[0] = 0x01;
FinalArray[1] = 0x10;

重构代码:

union bigbuf bigbuffer;
uint8 buffer[10];

struct diagram *dia = &bigbuffer.diagram;

dia->v01 = 0x01;
dia->v10 = 0x10;

// manipulate buffer ...

// copy buffer into struct ...
buffer[0] = 1;
memcpy(dia->buffer,buffer,10);

// get index and ID
Get_IndexANDID(&dia->index,&dia->ID);

现在事情已经完全填满了。


我们可以将所有数据直接放入结构中,而无需额外复制:

union bigbuf bigbuffer;

struct diagram *dia = &bigbuffer.diagram;

dia->v01 = 0x01;
dia->v10 = 0x10;

// manipulate buffer directly ...
uint8 *buffer = dia->buffer;
buffer[0] = 1;

// get index and ID
Get_IndexANDID(&dia->index,&dia->ID);

现在的大多数系统都是“little-endian”,所以上面的代码[可能]可以工作。

有限数量的系统(有些仍在使用)是“大端序”的。

因此,如果您不确定,可以按“网络字节顺序”存储数据,该顺序始终为“big-endian”:

union bigbuf bigbuffer;

struct diagram *dia = &bigbuffer.diagram;

dia->v01 = 0x01;
dia->v10 = 0x10;

// manipulate buffer directly ...
uint8 *buffer = dia->buffer;
buffer[0] = 1;

// get index and ID
Get_IndexANDID(&dia->index,&dia->ID);

// convert to network byte order
dia->index = htons(dia->index);
dia->ID = htons(dia->ID);

当收到这样的“数据包”时,我们需要反转这一点:

// receive packet from network ...

// convert to native/host byte order
dia->index = ntohs(dia->index);
dia->ID = ntohs(dia->ID);

评论

0赞 0___________ 11/13/2023
只有当字节序匹配时
0赞 Craig Estey 11/13/2023
@0____是的,我本来打算去的。但是,在2票接近的情况下,我想在被关闭之前得到答案。
0赞 0___________ 11/13/2023
不是一个好人。你假设没有填充等。这个答案尝试需要更多的工作才能正确。
2赞 0___________ 11/13/2023
因为你假设结构中没有填充。如果没有编译器扩展,就无法强制执行它(如)。__attribute__((packed))
1赞 chux - Reinstate Monica 11/13/2023
@CraigEstey虽然可能是真的,但一些独角兽平台可能会有所不同。考虑至少检测一个有问题的平台。sizeof(struct diagram) == 16static_assert(sizeof(struct diagram) == 16, "Strange struct diagram"):
2赞 0___________ 11/13/2023 #2

这可能是一个错别字

FinalArray[1] = 0x01;
FinalArray[2] = 0x10;

因为索引从 C 语言开始。0

您需要知道接口所需的字节序

void bigEndian(uint8_t *array, uint16_t val)
{
    array[0] = val >> 8;
    array[1] = val;    
}

void littleEndian(uint8_t *array, uint16_t val)
{
    array[1] = val >> 8;
    array[0] = val;    
}

uint8_t *formArray(uint8_t *array, const uint8_t *buffer, const uint16_t index, const uint16_t ID, int endianess)
{
    array[0] = 0x1;
    array[1] = 0x10;
    memcpy(array + 2, buffer, 10);
    if(endianess)
    {
        bigEndian(array + 12, index);
        bigEndian(array + 14, ID);
    }
    else
    {
        littleEndian(array + 12, index);
        littleEndian(array + 14, ID);
    }
    return array;
}