Can I populate a struct
by treating it as an array of unsigned char
values?
我可以通过将结构视为无符号字符值数组来填充结构吗?
I receive character data over the RS232 UART from a Microcontroller. Using C, how can I deserialize the char Array in my Datatypes uint16_t, uin32_t, int32_t[], ...
我通过RS232 UART从微控制器接收字符数据。使用C,我如何反序列化我的数据类型中的char数组uint16_t,uin32_t,int32_t [],...
e.g.
uin16_t StartID = ARRAY[0];
uin16_t EndID = ARRAY[246];
... is there something like this ? In C# there are effective functions for deserialization but im not that in C
......有这样的东西吗?在C#中有反序列化的有效功能,但不是在C中
for later
if (StartID == 11)
printf("good");
else
printf("bad");
I made this struct to work easier later with the Data. Is there a way to get the Data from my ARRAY[248] into my struct?
我以后使用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 个解决方案
#1
0
C has a feature called pointers
:
C有一个叫做指针的功能:
uin16_t *StartID = (void*)&ARRAY[0];
uin16_t *EndID = (void*)&ARRAY[246];
Other means to access data under another format include unions
:
以其他格式访问数据的其他方法包括工会:
union
{
uint32_t *u32;
uint16_t *u16;
uint8_t *u8;
} u;
As you can see, sometimes features do not need a dedicated function.
如您所见,有时功能不需要专用功能。
Beware however that alignment issues could arise on some platforms because of accessing data in such a way.
但请注意,由于以这种方式访问数据,在某些平台上可能会出现对齐问题。
#2
0
There are a number of similar approaches. You could use a C union
, which avoids the use of explicit pointers. You could use 'memcpy' to copy the contents of the unsigned char[]
into the memory of a DATA_POS
structure. Or you could write directly over that memory while reading from the serial port.
有许多类似的方法。您可以使用C联合,这可以避免使用显式指针。您可以使用'memcpy'将unsigned char []的内容复制到DATA_POS结构的内存中。或者,您可以在从串行端口读取时直接在该存储器上写入。
You didn't mention whether endianness is a concern, so I'll address that too.
你没有提到endianness是否是一个问题,所以我也会解决这个问题。
A union
lets you access the same block of memory as different data types. For example:
通过联合,您可以访问与不同数据类型相同的内存块。例如:
#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;
}
The above code treats the same sizeof(int)
bytes as a string of character values, and prints the numeric value of each.
上面的代码将相同的sizeof(int)字节视为一串字符值,并打印每个字符的数值。
Based on your code, you're looking for a union like
根据你的代码,你正在寻找像这样的联盟
union data_representation {
unsigned char char_data[248];
DATA_POS data_pos;
};
union data_representation data;
This would let you fill data.char_data
from the serial part, but refer to data.data_pos.StartID
from your code.
这将允许您从串行部分填充data.char_data,但请参阅代码中的data.data_pos.StartID。
Note, however, that different architectures can store the individual bytes of an integer in different order. Intel architectures traditionally use small-endian representations. The output of the code above will be different on x86:
但请注意,不同的体系结构可以按不同的顺序存储整数的各个字节。英特尔架构传统上使用小端表示。上面代码的输出在x86上会有所不同:
Character value is: cd
Character value is: ab
Character value is: 34
Character value is: 12
and SPARC:
Character value is: 12
Character value is: 34
Character value is: ab
Character value is: cd
The safest general approach is to send big-endian data between systems (in this case, via the serial port) and use ntohs
/ ntohl
to convert to the local host's representation. These functions convert "network" (big-endian) short (ntohs
) or long (ntohl
) data to whatever format is used by the local system. ntoh
means n
etwork to
h
ost, and the suffix is for s
hort or l
ong values. There are corresponding htons
and htonl
functions for converting from the host format into big-endian.
最安全的通用方法是在系统之间发送大端数据(在这种情况下,通过串行端口)并使用ntohs / ntohl转换为本地主机的表示。这些函数将“网络”(大端)短(ntohs)或长(ntohl)数据转换为本地系统使用的任何格式。 ntoh表示网络托管,后缀表示短值或长值。有相应的htons和htonl函数用于从主机格式转换为big-endian。
So you'd still populate data.char_data
, but read the data using ntohs(data.data_pos.StartID)
and ntohl(data.data_pos.POS04[1])
to get the native values.
所以你仍然填充data.char_data,但是使用ntohs(data.data_pos.StartID)和ntohl(data.data_pos.POS04 [1])读取数据以获取本机值。
It might even make sense to make your own conversion routines so you don't have ntohl
/ntohs sprinkled throughout your code later. For example, the
convert_to_host_format` function below converts a 248-character input array to a DATA_POS structure with the appropriate endianness.
制作自己的转换例程甚至可能是有意义的,因此您以后的代码中不会出现ntohl / ntoh。例如,下面的contvert_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;
}
If you wanted to skip the union
, memcpy
could be used to achieve the same results by writing directly over the memory holding the contents of DATA_POS
:
如果你想跳过联合,可以通过直接写入包含DATA_POS内容的内存来使用memcpy来获得相同的结果:
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;
}
You could even use a pointer while reading the UART data to write directly into the DATA_POS structure. The below treats the address of the structure (&data
) as an unsigned character pointer.
您甚至可以在读取UART数据时使用指针直接写入DATA_POS结构。下面将结构(&data)的地址视为无符号字符指针。
It would still be a good idea to use a function like the convert_to_host_format structure above to address endianness concerns. If you don't need to be able to run on multiple architectures, though, the following should be enough to meet your needs.
使用类似上面的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();
}
Please let me know if there's anything you'd like me to clarify.
如果您有什么需要我澄清的话,请告诉我。
#1
0
C has a feature called pointers
:
C有一个叫做指针的功能:
uin16_t *StartID = (void*)&ARRAY[0];
uin16_t *EndID = (void*)&ARRAY[246];
Other means to access data under another format include unions
:
以其他格式访问数据的其他方法包括工会:
union
{
uint32_t *u32;
uint16_t *u16;
uint8_t *u8;
} u;
As you can see, sometimes features do not need a dedicated function.
如您所见,有时功能不需要专用功能。
Beware however that alignment issues could arise on some platforms because of accessing data in such a way.
但请注意,由于以这种方式访问数据,在某些平台上可能会出现对齐问题。
#2
0
There are a number of similar approaches. You could use a C union
, which avoids the use of explicit pointers. You could use 'memcpy' to copy the contents of the unsigned char[]
into the memory of a DATA_POS
structure. Or you could write directly over that memory while reading from the serial port.
有许多类似的方法。您可以使用C联合,这可以避免使用显式指针。您可以使用'memcpy'将unsigned char []的内容复制到DATA_POS结构的内存中。或者,您可以在从串行端口读取时直接在该存储器上写入。
You didn't mention whether endianness is a concern, so I'll address that too.
你没有提到endianness是否是一个问题,所以我也会解决这个问题。
A union
lets you access the same block of memory as different data types. For example:
通过联合,您可以访问与不同数据类型相同的内存块。例如:
#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;
}
The above code treats the same sizeof(int)
bytes as a string of character values, and prints the numeric value of each.
上面的代码将相同的sizeof(int)字节视为一串字符值,并打印每个字符的数值。
Based on your code, you're looking for a union like
根据你的代码,你正在寻找像这样的联盟
union data_representation {
unsigned char char_data[248];
DATA_POS data_pos;
};
union data_representation data;
This would let you fill data.char_data
from the serial part, but refer to data.data_pos.StartID
from your code.
这将允许您从串行部分填充data.char_data,但请参阅代码中的data.data_pos.StartID。
Note, however, that different architectures can store the individual bytes of an integer in different order. Intel architectures traditionally use small-endian representations. The output of the code above will be different on x86:
但请注意,不同的体系结构可以按不同的顺序存储整数的各个字节。英特尔架构传统上使用小端表示。上面代码的输出在x86上会有所不同:
Character value is: cd
Character value is: ab
Character value is: 34
Character value is: 12
and SPARC:
Character value is: 12
Character value is: 34
Character value is: ab
Character value is: cd
The safest general approach is to send big-endian data between systems (in this case, via the serial port) and use ntohs
/ ntohl
to convert to the local host's representation. These functions convert "network" (big-endian) short (ntohs
) or long (ntohl
) data to whatever format is used by the local system. ntoh
means n
etwork to
h
ost, and the suffix is for s
hort or l
ong values. There are corresponding htons
and htonl
functions for converting from the host format into big-endian.
最安全的通用方法是在系统之间发送大端数据(在这种情况下,通过串行端口)并使用ntohs / ntohl转换为本地主机的表示。这些函数将“网络”(大端)短(ntohs)或长(ntohl)数据转换为本地系统使用的任何格式。 ntoh表示网络托管,后缀表示短值或长值。有相应的htons和htonl函数用于从主机格式转换为big-endian。
So you'd still populate data.char_data
, but read the data using ntohs(data.data_pos.StartID)
and ntohl(data.data_pos.POS04[1])
to get the native values.
所以你仍然填充data.char_data,但是使用ntohs(data.data_pos.StartID)和ntohl(data.data_pos.POS04 [1])读取数据以获取本机值。
It might even make sense to make your own conversion routines so you don't have ntohl
/ntohs sprinkled throughout your code later. For example, the
convert_to_host_format` function below converts a 248-character input array to a DATA_POS structure with the appropriate endianness.
制作自己的转换例程甚至可能是有意义的,因此您以后的代码中不会出现ntohl / ntoh。例如,下面的contvert_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;
}
If you wanted to skip the union
, memcpy
could be used to achieve the same results by writing directly over the memory holding the contents of DATA_POS
:
如果你想跳过联合,可以通过直接写入包含DATA_POS内容的内存来使用memcpy来获得相同的结果:
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;
}
You could even use a pointer while reading the UART data to write directly into the DATA_POS structure. The below treats the address of the structure (&data
) as an unsigned character pointer.
您甚至可以在读取UART数据时使用指针直接写入DATA_POS结构。下面将结构(&data)的地址视为无符号字符指针。
It would still be a good idea to use a function like the convert_to_host_format structure above to address endianness concerns. If you don't need to be able to run on multiple architectures, though, the following should be enough to meet your needs.
使用类似上面的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();
}
Please let me know if there's anything you'd like me to clarify.
如果您有什么需要我澄清的话,请告诉我。