将char数组反序列化为int和int []以及struct?

时间:2012-09-01 03:38:14

标签: c arrays struct embedded deserialization

我可以将struct作为unsigned char值数组来填充{<1}}吗?

我通过RS232 UART从微控制器接收字符数据。使用C,如何在我的数据类型uint16_t,uin32_t,int32_t [],...

中反序列化char数组

e.g。

uin16_t StartID = ARRAY[0];
uin16_t EndID = ARRAY[246];

......有这样的东西吗? 在C#中有反序列化的有效函数,但不是在C

以后

if (StartID == 11)
    printf("good"); 
else 
    printf("bad");

我以后使用Data使这个结构更容易工作。有没有办法从我的ARRAY [248]中获取数据到我的结构中?

typedef struct
{
  //Header 6byte
  uint16_t StartID; // Check if its 1 or in hex 0b
  uint16_t ID;      
  uint16_t LoadID;  

  //Payload 240 byte
  int32_t POS01[3];  
  int32_t POS02[3];
  int32_t POS03[3];
  int32_t POS04[3];
  int32_t POS05[3];
  int32_t POS06[3];
  int32_t POS07[3];
  int32_t POS08[3];
  int32_t POS09[3];
  int32_t POS10[3];
  int32_t POS11[3];
  int32_t POS12[3];
  int32_t POS13[3];
  int32_t POS14[3];
  int32_t POS15[3];
  int32_t POS16[3];
  int32_t POS17[3];
  int32_t POS18[3];
  int32_t POS19[3];
  int32_t POS20[3];

  //End 2byte
  uint16_t EndID; // Check if its 47 or in hex 2F

} DATA_POS; //TOTAL = 248byte

2 个答案:

答案 0 :(得分:0)

C有一个名为pointers的功能:

uin16_t *StartID = (void*)&ARRAY[0];
uin16_t *EndID = (void*)&ARRAY[246];

以其他格式访问数据的其他方式包括unions

   union 
   {
      uint32_t *u32;
      uint16_t *u16;
      uint8_t  *u8;
   } u;

如您所见,有时功能不需要专用功能。

请注意,由于以这种方式访问​​数据,某些平台可能会出现对齐问题。

答案 1 :(得分:0)

有许多类似的方法。您可以使用C union,这可以避免使用显式指针。您可以使用'memcpy'将unsigned char[]的内容复制到DATA_POS结构的内存中。或者,您可以在从串行端口读取时直接在该存储器上写入。

你没有提到字节顺序是否值得关注,所以我也会解决这个问题。

使用union可以访问与不同数据类型相同的内存块。例如:

#include <stdio.h>

#define chars_per_int (sizeof(int) / sizeof(char))

// Note that every member of a union exists at the same memory location,
// so changing the value of one will change the value of all
union IntAsChars {
    unsigned int integerValue;
    unsigned char characterValue[chars_per_int];
};

int main() {
    int i;
    union IntAsChars value;

    value.integerValue = 0x1234abcd;

    for (i = 0; i < chars_per_int; i++) {
        printf("Character value is: %x\n", value.characterValue[i]);
    }

    return 0;
}

上面的代码将相同的sizeof(int)字节视为一串字符值,并打印每个字符值的数值。

根据您的代码,您正在寻找像

这样的联盟
union data_representation {
    unsigned char char_data[248];
    DATA_POS data_pos;
};

union data_representation data;

这样您就可以从序列部分填充data.char_data,但请参阅代码中的data.data_pos.StartID

但是,请注意,不同的体系结构可以按不同的顺序存储整数的各个字节。英特尔架构传统上使用小端表示。上面代码的输出在x86上会有所不同:

Character value is: cd
Character value is: ab
Character value is: 34
Character value is: 12

和SPARC:

Character value is: 12
Character value is: 34
Character value is: ab
Character value is: cd

最安全的通用方法是在系统之间发送大端数据(在这种情况下,通过串行端口),并使用ntohs / ntohl转换为本地主机的表示。这些函数将“网络”(big-endian)短(ntohs)或长(ntohl)数据转换为本地系统使用的任何格式。 ntoh表示n etwork to h ost,后缀适用于s hort或l ong值。有相应的htonshtonl函数可以从主机格式转换为big-endian。

因此,您仍然会填充data.char_data,但请使用ntohs(data.data_pos.StartID)ntohl(data.data_pos.POS04[1])阅读数据以获取原生值。

创建自己的转换例程甚至可能有意义,因此您没有ntohl / ntohs sprinkled throughout your code later. For example, the convert_to_host_format`函数,将248字符的输入数组转换为具有相应字节顺序的DATA_POS结构

void convert_POS_to_host_format (int32_t dest[3], int32_t src[3]) {
    dest[0] = ntohl(src[0]);
    dest[1] = ntohl(src[1]);
    dest[2] = ntohl(src[2]);
}

DATA_POS convert_to_host_format (char buffer[248]) {
    DATA_POS host_data;
    union data_representation data;

    memcpy((void*)data.char_data, (void*)buffer, sizeof(buffer));

    host_data.StartID = ntohs(data.data_pos.StartID);
    host_data.ID = ntohs(data.data_pos.ID);
    host_data.LoadID = ntohs(data.data_pos.LoadID);

    convert_POS_to_host_format (host_data.POS01, data.data_pos.POS01);
    convert_POS_to_host_format (host_data.POS02, data.data_pos.POS02);
    convert_POS_to_host_format (host_data.POS03, data.data_pos.POS03);

    /* ... */

    convert_POS_to_host_format (host_data.POS19, data.data_pos.POS19);
    convert_POS_to_host_format (host_data.POS20, data.data_pos.POS20);

    host_data.EndID = ntohs(data.data_pos.EndID);

    return host_data;
}

如果您想跳过union,可以使用memcpy直接在包含DATA_POS内容的内存中创建相同的结果:

void convert_POS_to_host_format (int32_t POS[3]) {
    POS[0] = ntohl(POS[0]);
    POS[1] = ntohl(POS[1]);
    POS[2] = ntohl(POS[2]);
}

DATA_POS convert_to_host_format (char buffer[sizeof(DATA_POS)]) {
    DATA_POS host_data;

    /* Write the contents of 'buffer' directly into the memory location of
     * 'host_data'.
    memcpy((void*)host_data, (void*)buffer, sizeof(DATA_POS));

    /* Convert values to host byte order in place. */
    host_data.StartID = ntohs(host_data.StartID);
    host_data.ID = ntohs(host_data.ID);
    host_data.LoadID = ntohs(host_data.LoadID);

    convert_POS_to_host_format (host_data.POS01);
    convert_POS_to_host_format (host_data.POS02);
    convert_POS_to_host_format (host_data.POS03);

    /* ... */

    convert_POS_to_host_format (host_data.POS19);
    convert_POS_to_host_format (host_data.POS20);

    host_data.EndID = ntohs(data.data_pos.EndID);

    return host_data;
}

读取 UART数据时,您甚至可以使用指针直接写入DATA_POS结构。下面将结构的地址(&data)视为无符号字符指针。

使用类似上面的convert_to_host_format结构的函数来解决字节顺序问题仍然是一个好主意。但是,如果您不需要能够在多种体系结构上运行,则以下内容应足以满足您的需求。

DATA_POS data;
int i;
char *write_buffer;

write_buffer = (unsigned char*) &data;

for (i = 0; i < sizeof(DATA_POS); i++) {
    write_buffer[i] = read_byte_from_uart();
}

如果有任何您希望我澄清的话,请告诉我。

相关问题