Skip to content

已知限制

使用 cjbind 生成绑定时,以下情况需要特别注意。

打包结构体与非默认对齐

仓颉缺少精确的对齐控制语法,因此 cjbind 无法可靠表达 #pragma pack__attribute__((packed)) 等改变布局规则的类型。当前遇到 packed 类型时会直接跳过生成,而不是冒险生成错误绑定。

Bitfield

位域现在已经可以生成绑定,但生成结果不是仓颉原生字段,而是“隐藏存储 + getter / setter”形式的访问接口。这意味着:

  • API 形态会和原始 C 结构体字段访问不同。
  • 对 ABI、对齐或二进制兼容性特别敏感的场景仍然建议手动检查生成结果。
  • packed bitfield 结构体依然不受支持。

Union

联合体当前会被生成为内部 blob 存储加上每个字段的读写辅助函数,而不是仓颉原生 union 语义。这对大多数 FFI 场景已经足够,但如果你依赖精细的别名行为或特定内存技巧,仍然应该手动审查生成代码。

宏求值

cjbind 会借助 clang 计算可求值的宏表达式,因此整数、浮点数和字符串字面量宏通常都能生成出来。但下面这些情况仍然可能被跳过:

  • 函数式宏。
  • clang 无法静态求值的复杂表达式。
  • NaN、Infinity、次正规浮点数等无法稳定映射到仓颉字面量的值。

不透明类型

cjbind 会尝试为不透明类型生成绑定代码,同时为其附加一个总是抛出异常的构造函数,但是用户仍然可能使用 zeroValue 来创建结构体的实例。不透明类型的内存布局并不总是保证正确,因此使用不透明类型时需要特别小心,通常不应该在仓颉侧进行内存分配,而是持有 C 侧返回的指针。

柔性数组成员(Flexible Array Members)

仓颉不支持柔性数组成员的原生语法,因此 cjbind 会把这类成员降级为 CPointer<T>。这可以让绑定继续生成,但不会自动补上长度信息、所有权语义或分配策略,这部分仍需调用方自己保证。

调用约定

cjbind 会尝试根据 C 代码中的函数签名推断调用约定,但是可能会出现错误。如果你发现绑定代码中的函数签名不正确,应该手动修改绑定代码。

由于仓颉文档对于 STDCALL 调用约定描述不清晰,因此当前生成的调用约定总是 CDECL。可以在 Issue#1595 中追踪这个问题的进展。

Objective-C 语义

--objc 模式已经支持接口、协议、分类、属性、方法、可空性和 block 参数,但它主要解决的是“声明生成”和“调用桥接”问题。对于以下内容,仍然建议结合目标框架手动审查:

  • 对象所有权与生命周期管理。
  • 特殊 ABI 或非常规消息发送约定。
  • 依赖框架约定而不是头文件语义的高级 API。

以 MIT 许可证发布