从结构中访问数组并将其转换为指针

时间:2017-04-10 20:46:16

标签: c arrays struct ampersand

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;那么为什么&符号(&)?

1 个答案:

答案 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草案的参考文献

  
      
  1. 一致性
    ...
      2如果违反约束之外的“应该”或“不应该”的要求,则   行为未定义......
      3在所有其他方面正确的程序,对正确的数据进行操作,包含   未指明的行为应为正确的程序 ......
  2.   

  

6.3.2.3指针
...

  7指向对象或不完整类型的指针可以转换为指向不同的指针   对象或不完整的类型。 如果生成的指针未正确对齐   指向类型,行为未定义。否则,当再次转换回来时,   结果应比较等于原始指针。 指向对象的指针时   转换为指向字符类型的指针,结果指向最低寻址字节   对象

  

6.5表达式
...

  6访问其存储值的对象的有效类型是声明的类型   对象,如果有的话。如果值通过a存储到没有声明类型的对象中   lvalue的类型不是字符类型,那么左值的类型就变成了   该访问的对象的有效类型以及不修改的后续访问   储存的价值。如果将值复制到没有使用声明类型的对象中   memcpy或memmove,或者被复制为字符类型数组,然后是有效类型   用于该访问的修改对象以及不修改该访问的后续访问   value是从中复制值的对象的有效类型(如果有)。对于   对没有声明类型的对象的所有其他访问,对象的有效类型是   只是用于访问的左值的类型。

  7对象的存储值只能由具有其中一个的左值表达式访问   以下类型:

     
      
  • atype与对象的有效类型兼容,
  •   
  • 与对象的有效类型兼容的类型的水化版本,
  •   
  • 对应于有效类型的有符号或无符号类型的类型   对象,
  •   
  • 对应于合格版本的有符号或无符号类型的类型   有效的对象类型,
  •   
  • 聚合或联合类型,其中包含上述类型之一   成员(包括,递归地,子集合或包含的联合的成员),或
  •   
  • 字符类型。
  •