C 将uint8_t数组复制到结构

C 将uint8_t数组复制到结构,c,memcpy,string-literals,C,Memcpy,String Literals,我有这个数组 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

我有这个数组

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数组
成员不是以null结尾的,
printf(“%s”),
将不知道何时遇到每个字符串的结尾

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

例如:

printf("%.*s", (int)sizeof(foo.dateOfBirth), foo.dateOfBirth);
相当于:

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

*
指定要打印的字符的“精度”。因此,在您的情况下,
出生日期
=精度/大小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" "\0" "DOE" "\0" "010119" "\0" "M" "\0" "FOO" "\0" "BAR";
    DataStructTypeDef foo;
    memcpy((void *)&foo, (void *)buffer, sizeof(DataStructTypeDef));
    printf("%s", foo.dateOfBirth); // Expected value 01012019
}
缓冲区看起来严重损坏,因为如果我将
“\0”“010119”
放为
“\0010119”
,它将以错误的方式解释转义。更好的解决方案可能是将其保持为一个,并将八进制序列完全写为
\000

uint8_t *buffer = "JOHN\000DOE\000010119\000M\000FOO\000BAR";
在这里,每个
\000
变成一个空字节,并且它不会与转义序列之一后面的
010119
冲突

或者,如果我获取原始缓冲字符串
“JOHN:DOE:010119:M:FOO:BAR”
,并在复制后替换所有
,则它可以工作,如下所示:

foo.pad1 = foo.pad2 = foo.pad3 = foo.pad4 = foo.pad5 = foo.pad6 = '\0';

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

  • 修改您的结构
  • 为每个字段添加一个额外字节以容纳“\0”字符。例如,用于

    uint8_t firstName[5];
    
    而不是

    uint8_t firstName[4];
    
  • 单独分析字段,并以“\0”结束每个字段

  • 不要一次复制整个缓冲区,而是一个接一个地复制元素。因为每个字段的大小是固定的,所以缓冲区开始的偏移量是固定的,这使得解析工作更容易。

    警告:“firstName总是由4个字符组成,lastName是3个字符,等等…”如果为false,则缺少空字符结尾的位置them@zerocoldTUN如果不以空字符结尾字符串,则假定存在by,则无法使用标准函数,因此没有printf/strcpy/strdup/…
    uint8_t lastName[3];
    表示lastName包含1或2个字符,然后是\0,而不是3个字符您的问题是什么?您是否知道C是如何模仿“string”的,它实际上在C中不是数据类型。您可能想了解以
    0
    结尾的
    char
    -数组的概念。“使用填充位”您称之为“位”事实上是一个
    字节
    ,或者更准确地说是一个
    单元
    。注意:C中不需要强制转换,建议使用sizeof对象。简化:
    memcpy(&foo,buffer,sizeof foo);
    易于正确编码、检查和维护。“我希望这是练习,而不是真正工作的真正结构。”有什么问题吗?@zerocoldTUN例如:1)你希望只使用名字,其中名字总是4个字母,姓氏总是3个字母?2) 您可以用1个字节作为尾随零展开
    firstName
    lastName
    ,而不是
    pad1
    pad2
    。3) 通常使用
    char
    array作为名称,而不是字节数组。事实上,这只是一个例子。我不处理名字和姓氏。事实上,我有一个EEPROM(内存),我用它来存储我的产品的数据。产品ID、生产日期、批号等。。。从内存读取数据会返回一个字符数组,而我是定义这些字段的人。我对每个数据使用固定长度的字段,例如:日期始终是DDMMYY,一月一日不是这样写的:1119。总是010119。所以是的:我100%确定所有字段大小都是固定的,这就是为什么我想将其直接存储到数据结构中。@zerocoldTUN:“100%确定所有字段大小都是固定的”数据中冒号(
    )的用法,尽管?@zerocoldTUN:
    '0'
    \0
    不一样。您是否真的试图用字符串“\0”初始化标量
    uint8_t pad1
    字段?如果否,这些字符串将在编译时自动连接成一个字符串。因此,所有这些
    “\0”
    都转化为一个
    \0
    。我之所以这样做,是因为如果不是这样,它会将它解释为一个不同的文本,当文本中的
    \0
    后面紧跟着一个
    \0
    时。知道了。我没有捕捉到字段之间缺少的
    。Re“它以错误的方式解释转义”:在C中,一个八进制转义序列有一到三个八进制数字。编译器正确地将
    “\001”
    解释为1。零可以用
    “\000”
    @alk指定:否,只有最后的“\0”将转换为2个空字节。连接的字符串没有额外的嵌入空字节,只有显式显示的字节。
    %.*s
    指定要输出的最大字符数。如果在此限制之前存在空终止符,则输出将在空终止符处停止。