提问人:HansPeterLoft 提问时间:7/5/2023 更新时间:7/5/2023 访问量:119
C - 在u16_array中转换结构,其中每个uint16_t仅表示一个字节
C - convert a struct in a u16_array, where each uint16_t represents only a byte
问:
我在德州仪器 C2000 微控制器上有一个非常讨厌的案例,它只能代表uin16_t而不是uint8_t。现在我有一个如下所示的结构,其中每个uint16_t仅表示一个字节的数据,这些数据将被写入外部 EEPROM:
typedef struct
{
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} MCL_Struct_t;
MCL_Struct_t struc_write = {0};
MCL_Struct_t struc_read = {0};
uint16_t *struc_write_handle = ((uint16_t *)&struc_write);
uint16_t *struc_read_handle = ((uint16_t *)&struc_read);
struc_write.a = 0x11112222;
struc_write.b = 0x11113333;
struc_write.c = 0x11114444;
struc_write.d = 0x11115555;
//call eeprom write
EEPROM_writeTransaction(eepromAddr, struc_write_handle, sizeof(MCL_Struct_t));
//read back eeprom
EEPROM_readTransaction(eepromAddr, sizeof(MCL_Struct_t));
//copy to struc_read
memcpy(struc_read_handle, &SPI_DMA_Handle.pSPIRXDMA->pbuffer[0], sizeof(MCL_Struct_t));
由于 SPI 只能按字节传输,因此uint16_t数据作为字节处理,因此我只编写类似 struc_write.a = 0x00110022 等的内容。
我怎样才能使我的句柄按字节指向数据?
答:
0赞
Diram_T
7/5/2023
#1
如果底层架构在物理上无法进行字节寻址,那么您就不走运了,尽管从您的问题中尚不清楚是否如此。
如果你的微控制器可以按字节处理(据我所知,我认为应该是这样),那么它就是一个简单的强制转换来键入指针:char
char* addr = (char*) &struct_write.a;
char lower_byte = *addr;
char upper_byte = *(addr + 1);
否则,您可以使用移位操作来执行此操作,但请记住,这将占用两倍的内存:
uint6_t lower_byte = struct_write.a & (0x00FF);
uint6_t upper_byte = (struct_write.a >> 16) & (0x00FF);
我建议您进一步研究微控制器的架构并检查指令集架构。
评论
0赞
Aconcagua
7/5/2023
“简单转换为字符
类型指针”——在这种情况下很可能不是:没有可用的数据类型是 16 而不是 8 的有力指标(我知道那里有这样的 TI 器件......uint8_t
CHAR_BIT
sizeof(char) == sizeof(int16_t)
0赞
Diram_T
7/5/2023
这就是为什么我在前面加上一个介词“如果微控制器可以按字节处理”:)
0赞
Aconcagua
7/5/2023
旁注:为什么要在十六进制文字周围加上括号?只是使代码更难阅读,没有任何好处。请不要这样做。实际上,在对无符号类型进行左移后,您根本不需要屏蔽最重要的位,无论如何它们总是为 0(但如果为负数,则在有符号时定义实现)。
0赞
Aconcagua
7/5/2023
实际上,在给定的情况下,您甚至不必为低部分遮盖高位,无论如何它们都会被忽略......如果 API 发生变化?好吧,无论如何,我们都会添加多余的字节(零或看似垃圾),因此无论有没有;),实现都会中断
0赞
Diram_T
7/5/2023
我同意它们没有带来任何好处,但它使人们更容易注意到以后可以用宏观定义替换的表达式部分。我也同意未签名的班次部分。
2赞
Aconcagua
7/5/2023
#2
看起来好像 EEPROM 实现是为了将单个字符视为 8 字节值,即使在您的系统上显然是 16(函数签名很可能基于或直接)。CHAR_BIT
char
unsigned char
在这种情况下,你就不能直接写入整个结构,尽管这样做无论如何都是有问题的,因为存在潜在的填充字节(通常,不是在具体情况下)和字节顺序问题。因此,我建议显式序列化,无论您在哪种架构上,您都可以获得定义良好的行为:
void serialize(uint32_t value, char buffer[])
{
// for little endian byte order:
buffer[0] = value >> 0 & 0xff;
buffer[1] = value >> 8 & 0xff;
buffer[2] = value >> 16 & 0xff;
buffer[3] = value >> 24 & 0xff;
// ^^
// revert order of shifts for big endian byte order
}
char* serialize_s(uint32_t value, size_t length, char buffer[])
{
return length < 4 ? NULL : (serialize(value, buffer), buffer + 4);
}
uint32_t deserialize(char buffer[])
{
uint32_t value
= (uint32_t)(buffer[0] & 0xff) << 0
| (uint32_t)(buffer[1] & 0xff) << 8
| (uint32_t)(buffer[2] & 0xff) << 16
| (uint32_t)(buffer[3] & 0xff) << 24;
return value;
}
char* deserialize_s(uint32_t* value, size_t length, char buffer[])
{
return !value || length < 4
? NULL : (*value = deserialize(buffer), buffer + 4);
}
char buffer[16];
serialize(struct_write.a, buffer + 0);
serialize(struct_write.b, buffer + 4);
serialize(struct_write.c, buffer + 8);
serialize(struct_write.d, buffer + 12);
// send buffer
// receive buffer
struct_write.a = deserialize(buffer + 0);
struct_write.b = deserialize(buffer + 4);
struct_write.c = deserialize(buffer + 8);
struct_write.d = deserialize(buffer + 12);
评论
0赞
Shark
7/5/2023
呵呵,我不太明白这部分你在哪里做,你是想 OR () 他们还是这样做,因为它是,它不会重新分配 4 次吗?还是我的 C 真的生锈了?deserialize(char buffer[])
uint32_t value = highestByte = nextByte = nextByte = lowestByte;
|
|=
0赞
Aconcagua
7/5/2023
@Shark 复制粘贴错误...当然是,谢谢你的提示。|
0赞
Shark
7/6/2023
啊,没问题,不客气。我只是想,也许这是一些奇怪的伎俩,我对:)一无所知
0赞
dalfaB
7/5/2023
#3
在这里,我们有===。
A 是一个字节,但一个字节是 2 个八位字节。
不可能在八位字节上有指针。如果必须发送/接收八位字节,则必须通过转换函数来实现。sizeof(char)
sizeof(uint16_t)
sizeof(int)
1
char
typedef union BiOctets {
uint16_t u16; // 2 octets
unsigned char uc; // also 2 octets
struct { // also 2 octets
unsigned char high : 8;
unsigned char low : 8; // cannot take address of low
//Note: depending en endianess of C2000, may be high and low must be swapped
};
} BiOctets;
// access to an octet in an array of bytes
unsigned char BiOctetToOctet( BiOctets bi[], int index ) {
if ( index & 1 )
return bi[index>>1].low; // odd values is low part
else
return bi[index>>1].high; // even values is high part
} // notice that returns a byte where high octet is null, it's an octet
// insert an octet in array of bytes
void OctetToBiOctet( BiOctets bi[], int index, unsigned char value ) {
if ( index & 1 )
bi[index>>1].low = value;
else
bi[index>>1].high = value;
} // notice that 'value' is supposed to have null high octet, it's an octet
// then these function must be used each time you have to deal with octets
评论
uint16_t