如何在Gnu Smalltalk中向C函数传递回调函数?
Gnu Smalltalk C回调未触发的排查与解决
以下是针对你代码中回调未输出问题的几个排查方向:
1. 修正Smalltalk侧的C调用参数类型
你当前在init:方法的<cCall>注解里,把回调参数类型声明为#smalltalk,这是错误的。Gnu Smalltalk中传递CCallbackDescriptor实例给C函数时,参数类型应该匹配C侧的函数指针类型,正确声明应为#pointer:
XFrames class >> init: a b: bb c: cc onInit: onInitCb [ <cCall: 'init' returning: #void args: #(#string #string #string #pointer)> ]
2. 确认C侧正确调用回调
检查你的C语言init函数实现,必须显式调用传入的回调指针,且签名完全匹配(无参、返回void)。示例C代码如下:
void init(const char* assets_path, const char* cfg1, const char* cfg2, void (*on_init)(void)) { // 执行初始化逻辑 // 必须调用回调,否则Smalltalk侧不会触发 if (on_init != NULL) { on_init(); } }
3. 避免回调描述符被垃圾回收
如果C侧需要长期持有回调指针,你创建的callbackDescriptor3作为局部变量可能被Smalltalk的垃圾回收器回收,导致回调无法执行。可以将其声明为全局变量:
"声明全局回调描述符" callbackDescriptor3 := CCallbackDescriptor for: [XFrames test] returning: #void withArgs: #(). XFrames init: './assets' b: '{}' c: '{}' onInit: callbackDescriptor3.
4. 强制刷新Transcript输出
有时候Transcript的内容不会立即显示,需要手动触发刷新。修改test方法:
XFrames class >> test [ Transcript show: 'Callback called with no arguments'; nl. Transcript flush. ]
5. 验证回调签名一致性
确保Smalltalk中CCallbackDescriptor的返回值、参数列表和C侧的函数指针完全一致。如果C侧回调后续添加了参数,需同步修改withArgs的内容,比如C侧是void (*cb)(int),Smalltalk里就要写成withArgs: #(#int)。
内容的提问来源于stack exchange,提问作者Andrea Mancuso
相关产品推荐
相关产品推荐

