请考虑以下代码。
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_3
中的field_4
和my_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, ...);
在调用my_struct
之前在inalterable_my_struct
和ext_function
之间投射指针是否安全(如下所示)?
void call_ext_function(my_struct* ms){
inalterable_my_struct* ims = (inalterable_my_struct*)ms;
ext_function(ims, ...);
}
答案 0 :(得分:7)
我认为这不是一个好主意。
被调用函数总是可以抛弃任何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;
}
更清洁,除非你每秒数千次这样做,否则性能损失应该很小。
如果函数触及它,你可能也必须伪造基于指针的数据。
答案 1 :(得分: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 s2
,t2
,tp2
指向的类型或{{1}不兼容}}
此外,具有不同限定符的两种类型不被视为兼容:
要兼容两种合格类型,两者都应具有相同的合格版本 兼容类型;说明符或限定符列表中类型限定符的顺序 不会影响指定的类型。
更干净的方法是完全隐藏您的int
,将其替换为隐藏的句柄(struct
之上的typedef
)并提供操作void*
元素的函数{1}}。通过这种方式,您可以完全控制struct
的结构:您可以随意重命名其字段,根据需要随意更改布局,更改字段的基础类型,以及执行此操作当您的客户知道struct
的内部布局时,您通常会避免的其他事情。
答案 2 :(得分:2)
我认为这不是一个好主意,因为很难跟踪结构是否已被强制转换(特别是如果代码很大)。同时将其强制转换为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 ...);
我在上面的调用中使指针也保持不变,但这不是必需的。
答案 3 :(得分:-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 :(得分:-2)
写入曾经是const
的成员可能不安全。它们可能已被编译器/链接器和操作系统放入只读存储器中。请参阅 How is read-only memory implemented in C? 。