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

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, ...);,c,casting,C,Casting,我想允许ext\u function(由第三方编写)只修改我的结构中的字段3和字段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

我想允许
ext\u function
(由第三方编写)只修改
我的结构中的
字段3
字段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\u函数
之前,在
my\u struct
inalterable\u my\u struct
之间强制转换指针是否安全(如下所示)


我认为这不是个好主意

被调用的函数始终可以丢弃任何
常量
: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;
}
要干净得多,除非每秒执行数千次,否则性能损失应该很小


如果函数接触到指针数据,您可能也必须伪造它。

它可能会在大多数编译器上工作,即使标准没有对它做任何说明。如果你真的需要的话,你甚至可以通过工会做一些更方便的事情。除非它不会改变任何事情

这就是为什么它不会改变任何事情:

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

根据C99标准,两个
struct
s即使声明相同,也不会有兼容的类型。根据第6.7.7.5节:

示例2在声明之后

类型
t1
tp1
指向的类型兼容。类型
t1
也与类型
struct s1
兼容,但与类型
struct s2
t2
、由
tp2
int
指向的类型不兼容

此外,具有不同限定符的两种类型被视为不兼容:

对于要兼容的两种合格类型,两者应具有相同的合格版本 兼容类型的;类型限定符在说明符或限定符列表中的顺序 不影响指定的类型


一种更干净的方法是将
结构
全部隐藏起来,用一个模糊的句柄(位于
void*
之上的
typedef
替换它,并提供操作
结构
元素的函数。通过这种方式,您可以完全控制
结构的结构:您可以随意重命名其字段,尽可能频繁地更改布局,更改字段的基本类型,当客户知道
结构的内部布局时,您通常会避免做其他事情。

我认为这不是一个好主意,因为很难跟踪结构是否已强制转换(特别是如果代码很大)。此外,将其强制转换为常量并不保证以后不会将其强制转换为
非常量结构

解卷提供的解决方案非常好。另一种(更明显的)解决方案是将结构分成两个较小的部分

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

我在上面的调用中也使指针保持不变,但这不是必需的。

如果您不希望
ext\u function
修改
数据
,则应将其声明为
const uint8\u t*const data
typedef struct s1 { int x; } t1, *tp1;
typedef struct s2 { int x; } t2, *tp2;
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 ...);