已声明但从未定义的不透明结构

时间:2019-03-22 09:05:12

标签: c pointers struct language-lawyer

说我有以下声明

my_header.h

struct my_struct;

struct my_struct* my_struct_create();
void my_struct_use(struct my_struct*);
void my_struct_delete(struct my_struct*);

如果我们在my_header.c中对它们进行如下定义:

struct some_struct_came_from_3rdparty_lib;

struct my_struct* my_struct_create(){
    struct some_struct_came_from_3rdparty_lib *ptr = //create object
    return (struct my_struct*) ptr; //valid pointer conversion, ok
}
//void my_struct_use and void my_struct_delete definition omitted

问题 :以下代码是否会导致UB:

struct my_struct *ptr = my_struct_create();
my_struct_use(ptr);

我认为是的。即使标准允许我们转换正确对齐的指针6.3.2.3(p7)

  

指向对象类型的指针可能会转换为指向对象类型的指针   不同的对象类型。如果结果指针不正确   对于引用类型,该行为是不确定的。

struct my_struct*struct some_struct_came_from_3rdparty_lib*仍然是不兼容的类型6.7.6.1(p2)

  

要使两种指针类型兼容,两者应相同   合格,并且两者都应指向兼容类型的指针。

因此,通过语句struct some_struct_came_from_3rdparty_lib *中类型为struct my_struct *的左值访问(读取)struct my_struct *ptr = my_struct_create()会导致UB。这个理由有意义吗?

2 个答案:

答案 0 :(得分:2)

从技术上讲,这取决于my_struct_use的工作。但是,如果它是理智的,并且它所做的全部都被投射回正确的类型,如下所示:

void my_struct_use(struct my_struct *ptr)
{
    struct some_struct_came_from_3rdparty_lib *use = (struct some_struct_came_from_3rdparty_lib*)ptr;
    // ... use ptr
}

那么就没有未定义的行为。您永远不会像其他任何类型一样访问类型struct some_struct_came_from_3rdparty_lib *的左值。在my_struct_use内部,ptr实际上是struct my_struct *类型的(它是由强制转换产生的,并产生一个新值)。然后完全可以将此(返回)转换为struct some_struct_came_from_3rdparty_lib *,并再次产生该类型的新值。

如果您改为这样做,则会 为未定义行为:

struct some_struct_came_from_3rdparty_lib * use = *(struct some_struct_came_from_3rdparty_lib**)(&ptr);

然后,您将通过类型为ptr的左值(通过取消引用转换结果而产生)访问struct my_struct*,这是类型为struct some_struct_came_from_3rdparty_lib*的对象。

答案 1 :(得分:2)

简单地说,如果您的C文件具有

typedef struct some_struct_came_from_3rdparty_lib my_struct; 

那很好,否则就是不确​​定的行为。

或者,您可以定义my_struct使其包含some_struct_came_from_3rdparty_lib作为其第一位成员。

所有重要的事情是如何在.c文件中的指针之间进行转换以及如何访问数据。