在C中的struct指針之間進行轉換

[英]Cast between struct pointer in C


Please consider the following code.

請考慮以下代碼。

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

I want to allow ext_function (written by a third party) to modify only field_3and field_4 in my_struct. So I do the following:

我想允許ext_function(由第三方編寫)僅修改my_struct中的field_3和field_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, ...);

Is it safe to cast pointers between my_struct and inalterable_my_struct before calling ext_function (as shown after)?

在調用ext_function之前在my_struct和inalterable_my_struct之間轉換指針是否安全(如下所示)?

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

5 个解决方案

#1


7  

I don't think this is a good idea.

我不認為這是個好主意。

The called function can always cast away any const:ness, and modify the data if it wants to.

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

If you can control the callpoints, it would be better to create a copy and call the function with a pointer to the copy, then copy back the two fields you care about:

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

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

much cleaner, and unless you do this thousands of times a second the performance penalty should really be minor.

更清潔,除非你每秒數千次這樣做,否則性能損失應該是微不足道的。

You might have to fake the pointer-based data too, if the function touches it.

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

#2


4  

According to the C99 standard, two structs would not have compatible types even if their declarations were identical. From the section 6.7.7.5:

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

EXAMPLE 2 After the declarations

例2聲明后

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

type t1 and the type pointed to by tp1 are compatible. Type t1 is also compatible with type struct s1, but not compatible with the types struct s2, t2, the type pointed to by tp2, or int.

類型t1和tp1指向的類型是兼容的。類型t1也與struct s1類型兼容,但與struct s2,t2類型(tp2或int指向的類型)不兼容。

Moreover, two types with different qualifiers are not considered compatible:

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

For two qualified types to be compatible, both shall have the identically qualified version of a compatible type; the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.

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

A cleaner approach would be to hide your struct altogether, replace it with an obscure handle (a typedef on top of void*) and provide functions for manipulating the elements of the struct. This way you would retain full control over the structure of your struct: you would be able to rename its fields at will, change the layout as much and as often as you wish, change underlying types of the fields, and do other things that you normally avoid when the inner layout of the struct is known to your clients.

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

#3


2  

I don't think it's a good idea, because it is hard to track whether the structure has been cast or not (especially if the code is large). Also casting it into const does not guarantee that it won't be cast to a non-const structure later.

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

The solution provided by unwind is a very good one. An alternate (and more obvious) solution would be to split the structure into two smaller parts.

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

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

I have made the pointer also constant in the above call, but that is not necessary.

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

#4


-2  

It will probably work on most compliers even though the standard doesn't say anything about it. You can probably even do something more portable with a union if you really have to. Except it won't change anything.

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

This is why it won't change anything:

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

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

#5


-2  

Writing to the members that used to be const may not be safe. They may have been put in read-only memory by the compiler/linker and the operation system. See How is read-only memory implemented in C?.

寫入以前是const的成員可能不安全。它們可能已被編譯器/鏈接器和操作系統放入只讀存儲器中。請參閱如何在C?中實現只讀內存。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2012/12/03/72532f79c304e6467e83a388814b5323.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com