2017-04-10 74 views
0
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-> data”符号?从结构中访问数组并将其转换为指针

我的理解是,函数“请求”接收指针“msg”到一个结构。 msg-> data从msg(“data”是一个数组)指向的结构中检索指针“data”,然后将其转换为另一个指针类型(struct request *)。

所以那部分应该是(struct request *)msg-> data;那么为什么&符号(&)?

+0

注意:转换不仅是错误的,而且转让也会调用未定义的行为(实际上是赋值后的访问)。你的代码违反了有效的类型规则。 – Olaf

+0

*“msg-> data检索指针”data“”* - 否,它访问* array *数据。阵列在95%的使用中衰减至指针。 – StoryTeller

+0

除了有效性之外,'&msg-> data'表示为指针类型'uint8_t(*)[10]',而'msg-> data'表示为'uint8_t *'。这并不重要,因为无论何时抛出类型,并将其转换为希望对齐的'struct request *'。 – WhozCraig

回答

1

嗯,这个代码是不是C,因为__attribute__((packed))仅在GCC和其他一些具体的实施有效的,但肯定是在标准C.

不存在

但提供sizeof(struct message) <= 10,该代码的其余部分是正确的代码根据4. Conformance但包含unspecied行为,并可能包含根据实施

  • request(&devices[0]);void request(struct message *msg) {...}未定义行为:OK: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]。但是,这将在所有已知的实施所接受,因为实际上在内部处理相同的字符数组(显式)和分配的内存(没有声明型) - 仅仅是因为他们需要实现malloc(见Is it possible to write a conformant implementation of malloc in C?

其余代码不包含其他问题。但是应该注意的是,如果__attribute__(packed)被实现所尊敬,那么字段data将是该结构的第三个字节,这给出了一个奇怪的对齐。这可能会导致执行时崩溃,需要对某些类型严格对齐。


从n1256草案参考C99

  • 一致性
    ...
    2如果在 '' 必须 '' 或 '' 不得 ''违反约束条件的要求被违反, 行为未定义...
    3的程序是正确在所有其他方面,上正确的数据操作时,含有 未指定的行为应是正确的程序 ...
  • 6.3。 2.3指针
    ...
    7指向对象或不完整类型的指针可能被转换为指向不同的对象或指针的指针完整类型。 如果生成的指针未针对 指向类型正确对齐,则行为未定义。否则,当再次转换时, 结果应与原始指针相等。 当指向对象的指针 转换为指向字符类型的指针时,结果指向 对象的最低寻址字节。

    6.5表达式
    ...
    6用于向它的存储值的访问的有效类型的对象的是 对象声明的类型,如果有的话。如果值通过 类型不是字符类型的左值存储到没有声明类型的对象中,则左值的类型将变为该访问的对象的有效类型 ,并且对于后续访问修改 存储的值。如果使用 memcpy或memmove将值复制到没有声明类型的对象中,或者将其复制为字符类型的数组,则该访问的修改对象的有效类型 以及后续访问不会修改 value是从中复制值的对象的有效类型,如果它有一个。对于 对没有声明类型的对象的所有其他访问,对象的有效类型为 ,只是用于访问的左值的类型。

    7所述的对象应具有其存储的值由具有 之一以下类型的一个左值表达式仅访问:

    • atype的与有效类型的对象的兼容,
    • 的类型aqualified版本与有效类型的对象的兼容,
    • 一种类型,是有符号或对应于有效类型 对象的无符号类型,
    • 一种类型,是有符号或对应于合格v无符号类型所述 有效类型的对象的版为,
    • 的聚集体或联合类型包括其 成员之间的上述类型的一个(包括递归地,一个子聚集或含有联合的成员),或
    • 一个字符类型。
    相关问题