将 uint8_t 数组复制到结构

Copy a uint8_t array to a struct

我有这个数组

uint8_t *buffer = "JOHN:DOE:010119:M:FOO:BAR";

我想逐字段复制到数据结构

typedef struct{
  uint8_t firstName[5];
  uint8_t pad1;
  uint8_t lastName[4];
  uint8_t pad2;
  uint8_t dateOfBirth[7];
  uint8_t pad3;
  uint8_t genre;
  uint8_t pad4;
  uint8_t car[4];
  uint8_t pad5;
  uint8_t phone[4];
  uint8_t pad6;
}DataStructTypeDef;

假设所有长度都是固定的(例如,firstName 始终由 4 个字符组成,lastName 由 3 个字符组成,等等...)

我使用了这种方法:

DataStructTypeDef foo;
memcpy((void *)&foo, (void *)buffer, sizeof(DataStructTypeDef));

当我尝试打印 dateOfBirth 时,它显示了从 01012019 开始的整个数组,如下所示

int main(void)
{
  DataStructTypeDef foo;
  memcpy((void *)&foo, (void *)buffer, sizeof(DataStructTypeDef));
  printf("%s", foo.dateOfBirth); // It prints 010119:M:FOO:BAR
//printf("%s", foo.dateOfBirth); // Expected value 010119
  return 0;
}

由于您正在复制的 char array 成员不是空终止的,printf("%s", 不知道何时遇到每个字符串的结尾。

这可以在 printf 中通过限制打印的字符数量来控制...

例如:

printf("%.*s", (int)sizeof(foo.dateOfBirth), foo.dateOfBirth);

等效项是:

printf("%.6s", food.dateOfBirth);

.* 指定要打印的 "precision" 个字符。所以在你的情况下,dateOfBirth = precision/size 6.

固定结构

typedef struct {
    uint8_t firstName[4];
    uint8_t pad1;
    uint8_t lastName[3];
    uint8_t pad2;
    uint8_t dateOfBirth[6];
    uint8_t pad3;
    uint8_t genre;
    uint8_t pad4;
    uint8_t car[3];
    uint8_t pad5;
    uint8_t phone[3];
    uint8_t pad6;
}DataStructTypeDef;

这对我有用:

int main(void)
{
    uint8_t *buffer = "JOHN" "[=11=]" "DOE" "[=11=]" "010119" "[=11=]" "M" "[=11=]" "FOO" "[=11=]" "BAR";
    DataStructTypeDef foo;
    memcpy((void *)&foo, (void *)buffer, sizeof(DataStructTypeDef));
    printf("%s", foo.dateOfBirth); // Expected value 01012019
}

缓冲区看起来乱七八糟,因为如果我将 "[=14=]" "010119" 设为 "[=15=]10119",它会以错误的方式解释转义。更好的解决方案可能是将其保持为一个并将八进制序列完全写为 [=16=]0:

uint8_t *buffer = "JOHN[=12=]0DOE[=12=]0010119[=12=]0M[=12=]0FOO[=12=]0BAR";

在这里,每个 [=16=]0 都变成一个空字节,并且它不会与其中一个转义序列后面的 010119 冲突。

或者,如果我使用 "JOHN:DOE:010119:M:FOO:BAR" 的原始缓冲区字符串并在复制后替换所有 :,它会起作用,如下所示:

foo.pad1 = foo.pad2 = foo.pad3 = foo.pad4 = foo.pad5 = foo.pad6 = '[=13=]';

memcpy 之后添加:foo.pad1 = foo.pad2 = foo.pad3 = foo.pad4 = foo.pad5 = 0;。但我希望这是练习,而不是真正工作的真正结构。

  1. 修改结构

向每个字段添加一个额外的字节以容纳“\0”字符。例如使用

uint8_t firstName[5];

而不是

uint8_t firstName[4];
  1. 单独解析字段并以'\0'结束每个字段

与其一次性复制整个缓冲区,不如一个一个地复制元素。因为,每个字段的大小是固定的,从缓冲区开始的偏移量是固定的,这使得解析工作更容易。