2012-12-03 63 views
15

請考慮下面的代碼。在C中的結構指針之間施放C

typedef struct{ 
    int field_1; 
    int field_2; 
    int field_3; 
    int field_4; 

    uint8_t* data; 
    uint32_t data_size; 
} my_struct; 

void ext_function(inalterable_my_struct* ims, ...); 

我想允許ext_function(由第三方書面)僅修改field_3field_4my_struct。所以,我做到以下幾點:

typedef struct{ 
    const int field_1; 
    const int field_2; 
    int field_3; 
    int field_4; 

    const uint8_t* data; 
    const uint32_t data_size; 
} inalterable_my_struct; 

void ext_function(inalterable_my_struct* ims, ...); 

它是安全的主叫ext_function(如後所示)前投my_structinalterable_my_struct之間的指針?

void call_ext_function(my_struct* ms){ 
    inalterable_my_struct* ims = (inalterable_my_struct*)ms; 
    ext_function(ims, ...); 
} 
+0

如果你不想'ext_function'修改'data',你應該聲明它爲'const uint8_t * const data;'' – Henrik

回答

7

我不認爲這是一個好主意。

被調用的函數總是可以丟棄任何const:ness,並在需要時修改數據。

如果你能控制callpoints,這將是最好創建一個副本,並調用函數的指針複製,再複製回你所關心的兩個領域有關:

void call_ext_function(my_struct* ms) 
{ 
    my_struct tmp = *ms; 
    ext_function(&tmp, ...); 
    ms->field_3 = tmp.field_3; 
    ms->field_4 = tmp.field_4; 
} 

乾淨多了,除非你一秒做幾千次,否則表現的懲罰應該是微不足道的。

如果函數觸及它,您可能也必須僞造基於指針的數據。

-2

即使標準沒有對此提出任何意見,它也可能適用於大多數編制者。如果你真的需要,你甚至可以做一些更便攜的工會。除了它不會改變任何東西。

這就是爲什麼它不會改變任何東西:

$ cat foo.c 
struct foo { 
    const int a; 
    int b; 
}; 

void 
foo(struct foo *foo) 
{ 
    foo->a = 1; 
} 
$ cc -c foo.c 
foo.c: In function ‘foo’: 
foo.c:9: error: assignment of read-only member ‘a’ 
$ cc -Dconst= -c foo.c 
$ 
4

根據C99標準,兩個struct即使它們的聲明是相同的也不具有兼容類型。從部分6.7.7.5:

實施例2的聲明

typedef struct s1 { int x; } t1, *tp1; 
typedef struct s2 { int x; } t2, *tp2; 

類型t1和類型由tp1指向後是兼容的。類型t1也與struct s1類型兼容,但與類型struct s2t2tp2int指出的類型不兼容。

此外,兩種類型的具有不同限定符不被認爲是兼容的:

對於兩個限定類型是兼容的,兩者應具有兼容類型的相同合格 版本;說明符或限定符 列表中的類型限定符的順序不會影響指定的類型。

的清潔器的方法將是隱藏struct完全,用晦澀手柄(上的void*頂部typedef)替換它,並用於操縱所述struct的元件提供的功能。這樣你就可以完全控制你的struct的結構:你可以隨意重命名它的字段,根據需要隨意更改佈局,改變字段的底層類型,以及做其他事情通常在您的客戶已知struct的內部佈局時避免。

2

我不認爲這是一個好主意,因爲很難追蹤結構是否被轉換(特別是代碼很大時)。同樣將它強制轉換爲const並不保證它稍後不會投射到non-const structure

unwind提供的解決方案是非常好的解決方案。另一種(更明顯的)解決方案是將結構拆分成兩個較小的部分。

typedef struct{ 
    const int field_1; 
    const int field_2; 
    const uint8_t* data; 
    const uint32_t data_size; 
} inalterable_my_struct; 

typedef struct{ 
    int field_3; 
    int field_4; 
} my_struct; 

void ext_function(const inalterable_my_struct* const ims, my_struct* ms ...); 

我已經在上面的調用中使指針也不變,但這不是必需的。