You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

用字节数组替代void指针以隐藏指针是否属于不良编程实践?

用字节数组/联合体隐藏内部指针的实现是否属于不良编程实践?

你提到的这种写法借鉴自Godot 3,核心是通过将内部指针包装为固定大小的字节数组(或联合体),降低用户误修改内部数据的概率。直接给出结论:这不算典型的不良编程实践,但属于一种取巧的封装手段,存在局限性,且有更规范的替代方案。

三种写法的核心差异

你给出的三种实现,目标都是隐藏一个仅允许标准库/内部函数修改的指针:

  1. 字节数组版本:
#ifndef FILE_DATA_SIZE
#define FILE_DATA_SIZE sizeof(void *)
typedef struct {
    u8 dont_touch_data[FILE_DATA_SIZE];
} File;
#endif
  1. 联合体版本(兼顾内部操作便利性):
#ifndef FILE_DATA_SIZE
#define FILE_DATA_SIZE sizeof(void *)
typedef union {
    u8 dont_touch_data_array[FILE_DATA_SIZE];
    void *dont_touch_data_pointer;
} File;
#endif
  1. 直接暴露指针的版本:
typedef struct {
    void *dont_touch_data;
} File;

这种写法的合理性

它确实能达成你想要的效果:

  • 直接暴露void*时,用户可以轻松执行file->dont_touch_data = NULL;这类误操作;而字节数组版本需要用户刻意做强制类型转换(比如*(void**)file = NULL;)才能修改,大幅降低了无意误改的概率。
  • 联合体版本兼顾内部实现:库函数可以直接用指针成员操作,对外仅暴露数组,避免用户直接接触指针。

这种写法的局限性

  1. 无法彻底阻止刻意修改:只要用户愿意,依然可以通过类型转换绕过限制,只是提高了操作门槛,做不到真正的封装。
  2. 可读性与维护性差:其他开发者看到这个结构体时,会困惑为什么不用直接用指针,需要额外注释说明意图,增加了团队协作成本。
  3. 平台兼容性隐患:依赖sizeof(void*)与字节数组大小完全匹配,虽然绝大多数平台都符合,但在一些特殊嵌入式系统中,可能存在内存对齐或大小不一致的问题,引发潜在内存错误。
  4. 不符合C语言封装惯例:C语言中实现“隐藏内部状态”的标准做法是不透明指针(Opaque Pointer),而非这种取巧的包装方式。

更规范的替代方案:不透明指针

这是C语言实现封装的标准方式,能从根本上阻止用户访问内部数据:

  • 在头文件中仅声明结构体类型,不暴露任何成员:
// 头文件中
typedef struct File File;
  • 所有操作File的函数(如打开、关闭、读写)都在库的实现文件中定义,内部结构体的具体成员完全对外隐藏:
// 实现文件中
struct File {
    void *internal_data;
    // 其他内部成员
};

File* fopen(const char* path, const char* mode) {
    File* fp = malloc(sizeof(File));
    fp->internal_data = // 初始化内部指针
    return fp;
}

int fclose(File* fp) {
    // 清理内部资源
    free(fp);
    return 0;
}

这种方式不仅彻底阻止了用户访问内部数据,还符合C语言的设计惯例,可读性和可维护性都更好。

总结

你提到的写法有一定实用价值,能过滤大部分无意的误修改,但并非最优解。如果追求严格的封装和规范的代码,更推荐使用不透明指针方案。

内容的提问来源于stack exchange,提问作者Henrique Moisés

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 07:31:16