2017-04-10 44 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無符號類型所述 有效類型的對象的版爲,
    • 的聚集體或聯合類型包括其 成員之間的上述類型的一個(包括遞歸地,一個子聚集或含有聯合的成員),或
    • 一個字符類型。