我可以将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
答案 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值。有相应的htons
和htonl
函数可以从主机格式转换为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();
}
如果有任何您希望我澄清的话,请告诉我。