struct message {
uint8_t start;
uint16_t length;
uint8_t data[10];
uint8_t checkSum;
} __attribute__((packed));
struct message devices[10];
void request(struct message *msg) {
struct request *req = (struct request *)&msg->data;
req->operation = 1;
req->requesterAddress = MASTER_ADDRESS;
}
request(&devices[0]);
我的问题是,为什么&符号& msg->数据" ?
我的理解是功能"请求"接收指针" msg"到一个结构。 msg->数据检索指针"数据"来自" msg" (" data"是一个数组),然后它被转换为另一个指针类型(struct request *)。
那部分应该是(struct request *)msg-> data;那么为什么&符号(&)?
答案 0 :(得分:1)
嗯,这段代码不是C,因为__attribute__((packed))
仅在gcc和其他一些特定实现中有效,但在标准C中肯定不存在。
但提供sizeof(struct message) <= 10
,其余代码根据4. Conformance
正确代码但包含未指定的行为,并且可能包含未定义的行为,具体取决于实现
request(&devices[0]);
和void request(struct message *msg) {...}
:好的:request
需要一个struct message *
并接收struct message
数组的第一个元素的地址 - 这里一切都很好struct request *req = (struct request *)&msg->data;
:这是最有趣的部分。
msg->data
是一个char数组,它是一个聚合。聚合的地址是其第一个字节的地址。不同地说(char *) &msg-> data
(聚合的第一个字节的地址)与msg->data
相同(数组衰减到指向其第一个元素的指针)(struct request *)&msg->data;
指向char的指针被转换为指向struct request
的指针。根据实现,没有什么能保证指针正确对齐。如果不是,则根据6.3.2.3指针§7,这是未定义的行为。如果是,则根据6.5表达式§6-7,我们仍然有未指定的行为,因为新指针将用于存储未指定的元素声明的char[10]
类型。但是这将被所有已知的实现所接受,因为在内部它们处理相同的char数组(显式类型)和分配的内存(没有声明的类型) - 只是因为它们需要实现malloc
(参见Is it possible to write a conformant implementation of malloc in C?) 其余代码不包含其他问题。但应该注意的是,如果__attribute__(packed)
被实现所尊重,则字段data
将是结构的第三个字节,这给出了一个奇怪的对齐。这可能导致实现崩溃,需要严格对齐某些类型。
来自C12的n1256草案的参考文献
- 一致性
醇>
...
2如果违反约束之外的“应该”或“不应该”的要求,则 行为未定义......
3在所有其他方面正确的程序,对正确的数据进行操作,包含 未指明的行为应为正确的程序 ......
6.3.2.3指针
...
7指向对象或不完整类型的指针可以转换为指向不同的指针 对象或不完整的类型。 如果生成的指针未正确对齐 指向类型,行为未定义。否则,当再次转换回来时, 结果应比较等于原始指针。 指向对象的指针时 转换为指向字符类型的指针,结果指向最低寻址字节 对象。
6.5表达式
...
6访问其存储值的对象的有效类型是声明的类型 对象,如果有的话。如果值通过a存储到没有声明类型的对象中 lvalue的类型不是字符类型,那么左值的类型就变成了 该访问的对象的有效类型以及不修改的后续访问 储存的价值。如果将值复制到没有使用声明类型的对象中 memcpy或memmove,或者被复制为字符类型数组,然后是有效类型 用于该访问的修改对象以及不修改该访问的后续访问 value是从中复制值的对象的有效类型(如果有)。对于 对没有声明类型的对象的所有其他访问,对象的有效类型是 只是用于访问的左值的类型。
7对象的存储值只能由具有其中一个的左值表达式访问 以下类型:
- atype与对象的有效类型兼容,
- 与对象的有效类型兼容的类型的水化版本,
- 对应于有效类型的有符号或无符号类型的类型 对象,
- 对应于合格版本的有符号或无符号类型的类型 有效的对象类型,
- 聚合或联合类型,其中包含上述类型之一 成员(包括,递归地,子集合或包含的联合的成员),或
- 字符类型。