已知限制
使用 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。