1

我可以struct通过将它视为一个值数组来填充它unsigned char吗?

我通过 RS232 UART 从微控制器接收字符数据。使用 C,我如何反序列化我的数据类型 uint16_t、uin32_t、int32_t[]、...中的 char 数组

例如

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
4

2 回答 2

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;

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

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

于 2012-09-01T03:53:16.243 回答
0

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

你没有提到字节序是否是一个问题,所以我也会解决这个问题。

Aunion允许您以不同的数据类型访问相同的内存块。例如:

#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转换为本地主机的表示。这些函数将“网络”(大端)短(ntohs)或长(ntohl)数据转换为本地系统使用的任何格式。ntoh表示network to host,后缀是short 或long 值。从主机格式转换为大端格式有相应的htons和函数。htonl

因此,您仍然需要填充,但使用和data.char_data读取数据以获取本机值。ntohs(data.data_pos.StartID)ntohl(data.data_pos.POS04[1])

制作自己的转换例程甚至可能有意义,这样您就没有下面的ntohl/ ntohs sprinkled throughout your code later. For example, theconvert_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();
}

如果您有什么需要我澄清的,请告诉我。

于 2012-09-01T22:15:30.877 回答