gpt4 book ai didi

c - 将 C 结构转换为另一个元素较少的结构是否安全?

转载 作者:太空狗 更新时间:2023-10-29 17:07:38 25 4
gpt4 key购买 nike

我正在尝试在 C 上执行 OOP(只是为了好玩),我想出了一种方法来进行数据抽象,方法是先有一个带有公共(public)部分的结构,然后有一个更大的带有公共(public)部分的结构,然后是私有(private)部分。通过这种方式,我在构造函数中创建了整个结构并将其转换为小结构。这是正确的还是会失败?

这是一个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// PUBLIC PART (header)
typedef struct string_public {
void (*print)( struct string_public * );
} *string;

string string_class_constructor( const char *s );
void string_class_destructor( string s );

struct {
string (*new)( const char * );
void (*delete)( string );
} string_class = { string_class_constructor, string_class_destructor };


// TEST PROGRAM ----------------------------------------------------------------
int main() {
string s = string_class.new( "Hello" );
s->print( s );
string_class.delete( s ); s = NULL;
return 0;
}
//------------------------------------------------------------------------------

// PRIVATE PART
typedef struct string_private {
// Public part
void (*print)( string );
// Private part
char *stringData;
} string_private;

void print( string s ) {
string_private *sp = (string_private *)( s );
puts( sp->stringData );
}

string string_class_constructor( const char *s ) {
string_private *obj = malloc( sizeof( string_private ) );
obj->stringData = malloc( strlen( s ) + 1 );
strcpy( obj->stringData, s );
obj->print = print;
return (string)( obj );
}

void string_class_destructor( string s ) {
string_private *sp = (string_private *)( s );
free( sp->stringData );
free( sp );
}

最佳答案

理论上,这可能是不安全的。允许两个单独声明的结构有不同的内部安排,因为绝对没有积极的要求让它们兼容。实际上,编译器不太可能为两个相同的成员列表实际生成不同的结构(除非某处有特定于实现的注释,此时赌注已关闭 - 但你会知道这一点)。

传统的解决方案是利用这样一个事实,即始终保证指向任何给定结构的指针与指向该结构的第一个元素的指针相同(即结构没有前导填充:C11,6.7.2.1。 15).这意味着您可以强制两个结构的前导元素不仅相同,而且严格兼容,方法是在两个结构的前导位置使用共享类型的值结构:

struct shared {
int a, b, c;
};
struct Foo {
struct shared base;
int d, e, f;
};
struct Bar {
struct shared base;
int x, y, z;
};

void work_on_shared(struct shared * s) { /**/ }

//...
struct Foo * f = //...
struct Bar * b = //...
work_on_shared((struct shared *)f);
work_on_shared((struct shared *)b);

这是完全符合并保证有效的,因为将共享元素打包到单个前导结构中意味着只有 FooBar 的前导元素的位置是曾经明确依赖。


在实践中对齐不太可能成为困扰您的问题。一个更紧迫的问题是 aliasing (即允许编译器假定指向不兼容类型的指针不会别名)。指向结构的指针始终与指向其成员类型之一的指针兼容,因此共享基策略不会给您带来任何问题;使用编译器未被强制标记为兼容的类型可能会导致它在某些情况下发出错误优化的代码,如果您不知道,这可能是很难找到的 Heisenbug。

关于c - 将 C 结构转换为另一个元素较少的结构是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28968515/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com