如何将变量指向不同结构的成员?这就是我想要做的,但第三行失败了。
volatile uint8_t tx_message_buffer[sizeof(MESSAGE)];
struct MESSAGE *tx_message = (MESSAGE *)tx_message_buffer;
struct PAYLOAD *tx_payload = (PAYLOAD *)tx_message->payload;
以下是结构定义。
#define MSG_MAX_PAYLOAD_LENGTH 64
typedef struct PAYLOAD {
uint8_t descriptor;
uint8_t parameters[MSG_MAX_PAYLOAD_LENGTH-1];
};
typedef struct MESSAGE {
uint8_t address;
uint8_t length;
PAYLOAD payload;
uint8_t checksum;
};
答案 0 :(得分:3)
此代码存在许多问题。
正如其他答案中所指出的,您无法设置指向PAYLOAD payload;
成员的指针,您需要指向其地址&tx_message->payload
。
typedef struct PAYLOAD {}
应为typedef struct {} PAYLOAD
。
(MESSAGE *)tx_message_buffer
是一个完全狂野的演员,会调用几个定义不明确的行为。首先,你永远不应该抛弃volatile
个限定词。但是,一旦您取消引用此结构,您将违反strict aliasing并调用未定义的行为。任何事情都可能发生。
要解决这些指针错误,您可以执行与此类似的操作:
typedef struct {
uint8_t address;
uint8_t length;
PAYLOAD payload;
uint8_t checksum;
} MESSAGE;
typedef union {
MESSAGE message;
uint8_t tx_message_buffer[sizeof(MESSAGE)];
} message_something;
此代码有效且定义明确。
使用结构来表示数据协议是不好的做法,因为您必须确保结构根本不包含填充。您MESSAGE
结构中的内存布局绝不能保证与数据协议的内存布局相对应。该结构可以具有填充字节以适应特定CPU的对齐要求。
根据您的可移植性要求,禁用使用非标准C(例如#pragma pack(1)
)的填充可能会也可能不够。要实现完全可移植性,您可能必须编写序列化/反序列化例程。
答案 1 :(得分:2)
您的代码中存在更大的问题:第二行的强制转换无效,因为struct MESSAGE
的存储通常可能具有与char[]
数组不同的对齐要求。例如,将descriptor
的类型更改为uint32_t
可能会在某些平台上强制整个结构的偶地址位置。
反之这样做是有效的,因为你可以将任何对象指针转换为char *
:
volatile struct MESSAGE tx_message;
volatile uint8_t *tx_message_buffer = (char*)tx_message;
第三行失败是因为你没有使用PAYLOAD
struct:
struct PAYLOAD tx_payload = &tx_message.payload;
无需转换结果,因为tx_message.payload
已经是正确的类型。
答案 2 :(得分:0)
使用,
PAYLOAD payload;
你得到的变量不是指针。意思是
message->payload;
不是指针。
您需要使用指针。
PAYLOAD * payload;
或者获取结构的地址
&message->payload;