在 C 中隐藏结构定义是一种好习惯吗?

Is it a good practice to hide structure definition in C?

在我看来,在 C 中隐藏结构的定义通常会使代码更安全,因为您在编译器的帮助下强制执行结构的任何成员都不能直接访问。

但是,它有一个缺点,即结构的用户无法声明其类型的变量以放入堆栈,因为这样结构的大小变得不可用(因此,用户必须通过 malloc() 在堆上进行分配,即使这是不受欢迎的。

这可以通过 alloca(3) function that is present in all major libc implementations, even though it does not conform to POSIX.

解决(部分)

考虑到这些优点和缺点,这样的设计总体上可以认为是好的吗?

lib.h中:

struct foo;
extern size_t foo_size;
int foo_get_bar(struct foo *);

lib.c中:

struct foo {
  int bar;
};

size_t foo_size = sizeof foo;

int foo_get_bar(struct foo *foo)
{
  return foo->bar;
}

example.c中:

#include "lib.h"

int bar(void)
{
  struct foo *foo = alloca(foo_size);
  foo_init(foo);
  return foo_get_bar(foo);
}

函数 bar 调用未定义的行为:foo 指向的结构未初始化。

如果您要隐藏结构细节,请提供一个 foo_create() 来分配一个并对其进行初始化,并提供一个 foo_finalize 来释放任何资源并释放它。

您提出的建议可以实现,但容易出错,不是通用解决方案。

是的,隐藏数据是个好习惯。

作为alloca(foo_size); 模式的替代方法,可以声明一个对齐的字符数组并执行指针转换。但是,指针转换不是完全可移植的。如果大小由变量而不是编译时常量定义,则字符数组需要是 VLA:

extern size_t size;

struct sfoo;

#include <stddef.h>

int main(void) {
  unsigned char _Alignas (max_align_t) cptr[size];
  // or unsigned char _Alignas (_Complex  long double) cptr[size];  // some widest type
  struct sfoo *sfooptr = (struct sfoo *) cptr;
  ...

如果 VLA 不需要或不可用,请将大小声明为常量 (#define foo_N 100),保证 至少 所需的大小。