我想对我的库隐藏我真正的 struct .
如果您坚持这样做,则在公共标头中使 struct 类型不透明.
在Private.h中,我有[struct Car_t
...和]
在一些公共的.h中,我有[struct Car_t
的定义,省略了一些落后成员]
现在,这段代码编译得很好.
很难说你说的"这"是什么意思.人们通常不会单独编译头文件.然而,如果你这样做了,那么我假设这两个头都不是#include
s,所以不会有一个expose 给另一个.
如果您还编译了使用这些头文件的代码,那么我必须假设没有同时使用这些头文件的转换单元#include
,因为如果这样做了,那么符合要求的编译器将不得不发出关于不匹配的诊断.假设没有代码同时看到两个头文件,这种差异本身不会成为编译失败的任何原因.
如果我没有创建任何新的公共汽车,应该可以省略(隐藏)*LoadValify?
大概不会吧.在某些情况下,在同一个程序中使用这两个不兼容的类型定义是可以的,但它们比您所描述的要严格得多.
这意味着从库中调用(公共领域)我的函数将收到相同的对象并且完全安全,对吗?
Absolutely not.无论如何都不是同一个对象(C只有按值传递的语义).一点也不安全.程序看起来像预期的那样工作的可能性取决于它试图做的事情的细节,但即使它看起来像您预期的那样工作,也可能存在隐藏的错误行为或在不常见的情况下出现错误行为,或者如果您更改编译选项或使用不同的编译器,或者当您以看似无关的方式修改代码时,它可能会崩溃.
详细信息:
C没有在不同的翻译单元中声明的the same struct 类型的任何含义.每个翻译单元的类型声明都有自己的类型声明.相反,C依赖于compatible类型的概念.在不同的翻译单元中声明的两种 struct 类型,都带有标记和成员,只有在标记相同、成员数量相同并且对应的成员具有兼容类型的情况下才兼容(这些并不是所有的要求).
因此,根据这些定义之一在一个翻译单元中声明的 struct 类型与根据另一个定义在不同翻译单元中声明的 struct 类型不兼容.两者都不是从那些彼此兼容的类型派生的类型,例如指向这些类型的指针或这些类型的限定版本,也不是包含具有这些类型的成员的联合或聚合,也不是从这些类型递归派生的成员.
如果同一外部函数标识符的声明声明了以任何方式从不兼容 struct 类型派生的类型中的返回或参数类型,则它们也不兼容.
如果程序通过左值访问对象,其类型与对象自身的有效类型不兼容(并且也不满足此处不适用的少数其他条件),则行为是未定义的.如果程序从该函数的声明范围内调用与其定义不兼容的函数,则该行为是未定义的.
如果您正在传递或返回有问题的 struct 类型的实例,则产生的UB很可能表现为严重的不当行为,例如程序崩溃和其他不正确的操作.如果您只是根据指向这些 struct 的指针进行工作,那么行为仍然是未定义的,但根据各种变量的不同,您可能会碰上似乎与您的期望一致的程序行为.这比明显的不当行为更糟糕,因为它可能隐藏着不明显的不当行为,或者在不常见的情况下可能仍然存在问题.
但如果我在公共领域创造新车呢?根据我的
理解,将是一个完全不同的对象类型(来自
公众);
一点儿没错.您可以创建它们,但不能使用您的私有库代码来创建它们.
因此,在本例中,我应该使用VALID*填充公共 struct
为了保持同样的大小?
不是的.这并不能挽救局势.
如何预留空间用于
我的隐私 struct _t?
这与空间无关.具有相同标签和大小的 struct 类型不足以使它们兼容,甚至不足以使它们达到seem兼容.
您有两个主要 Select :
不要试图隐藏成员,至少不要在库头文件中隐藏成员.如果您愿意,可以从您的documentation中省略私有成员,并可能明确警告只应访问公共成员.但即使这样也会有问题,因为如果在公共端创建 struct 的实例,私有成员应该如何获取有效值?
使 struct 不透明.也就是说,在公开方面,只提供一份前瞻性声明,没有任何成员:
struct Car_t;
typedef struct Car_t Car_t; // optional
公共端将不能自己创建实例,但它将能够处理pointers to个实例.它将需要依赖库函数来分配实例和访问它们的成员.