簡體   English   中英

在C中的struct指針之間轉換

[英]Cast between struct pointer in 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 (由第三方編寫)僅修改my_struct field_3field_4 所以我做了以下事情:

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, ...);
}

我不認為這是個好主意。

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

如果您可以控制調用點,最好創建一個副本並使用指向該副本的指針調用該函數,然后復制您關注的兩個字段:

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;
}

更清潔,除非你每秒數千次這樣做,否則性能損失應該很小。

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

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

例2聲明后

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

類型t1tp1指向的類型是兼容的。 類型t1也與struct s1類型兼容,但與struct s2t2類型( tp2int指向的類型)不兼容。

此外,具有不同限定符的兩種類型不被視為兼容:

要使兩種合格類型兼容,兩者都應具有相同類型的兼容類型; 說明符或限定符列表中類型限定符的順序不會影響指定的類型。

更簡潔的方法是完全隱藏你的struct ,用一個不起眼的句柄( void*之上的typedef替換它,並提供操作struct元素的struct 通過這種方式,您可以完全控制結構的struct :您可以隨意重命名其字段,根據需要隨意更改布局,更改字段的基礎類型,以及執行其他操作通常避免在客戶端知道struct的內部布局時。

我不認為這是一個好主意,因為很難跟蹤結構是否已被轉換(特別是如果代碼很大)。 同時將其轉換為const並不能保證以后不會將其強制轉換non-const structure

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

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 ...);

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

它可能適用於大多數編譯器,即使標准沒有說明任何內容。 如果你真的需要,你甚至可以用聯盟做一些更便攜的東西。 除了它不會改變任何東西。

這就是為什么它不會改變任何東西:

$ 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
$ 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM