有许多类似的方法。您可以使用 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
表示n
etwork to
h
ost,后缀是s
hort 或l
ong 值。从主机格式转换为大端格式有相应的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, 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();
}
如果您有什么需要我澄清的,请告诉我。