说我有以下声明
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。这个理由有意义吗?
答案 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文件中的指针之间进行转换以及如何访问数据。