9

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

然而,它有一个缺点,结构的用户不能声明其类型的变量要放入堆栈,因为结构的大小以这种方式变得不可用(因此,用户必须求助于分配堆通过,malloc()即使它是不可取的)。

这可以(部分)通过alloca(3)所有主要 libc 实现中存在的函数来解决,即使它不符合 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);
}
4

2 回答 2

3

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

作为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),保证至少与需要一样多。

于 2015-12-15T22:55:17.093 回答
2

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

如果要隐藏结构详细信息,请提供一个foo_create()分配一个并初始化它并foo_finalize释放任何资源并释放它的资源。

您提出的建议可以发挥作用,但容易出错并且不是通用解决方案。

于 2015-12-15T22:32:47.460 回答