我应该如何创建一个 (const char **) 以将其传递给 C 函数?
假设我的 const char ** 被命名为 prompts
然后:
user := 'User:' copyToHeap: #malloc:.
pwd := 'Password:' copyToHeap: #malloc:.
prompts := (ByteArray new: 64) copyToHeap: #malloc:.
prompts copyAt: 0 from: (user referentAddress asByteArraySize: 32) size: 4 startingAt: 1.
prompts copyAt: 31 from: (pwd referentAddress asByteArraySize: 32) size: 4 startingAt: 1.
所以 prompts
是一个 64 位数组,其中前 32 位是指向 user
的指针,而后 32 位是指向 pwd
的指针。
但是 C 函数不起作用。 在 GemStone 中工作正常:
prompts := CByteArray gcMalloc: 16.
user := CByteArray withAll: 'User:'.
pwd := CByteArray withAll: 'Password:'.
prompts uint64At: 0 put: user memoryAddress.
prompts uint64At: 8 put: pwd memoryAddress.
答案 0 :(得分:2)
DLLCC 提供了一些非常接近 C 的 API。 您需要一个包含两个字符指针的数组。
prompts := CIntegerType char pointerType gcMalloc: 2.
然后你可以像这样填充这个数组:
prompts at: 0 put: user.
prompts at: 1 put: pwd.
请注意,索引像 prompts[0]=user; prompts[1]=pwd;
一样模仿 C。
最后一件事,所有你malloc
,你必须然后free
,否则你会出现内存泄漏。
这意味着你应该更好地保护所有这些代码
["your protected code here"]
ensure: [prompts free. user free. pwd free]`
...或更糟...
["your protected code here"]
ensure:
[prompts isNil ifFalse: [prompts free].
"etc..."]`.
在早期开发中,我建议你最好使用gcMalloc
和gcMalloc:
。
事后思考
gcMalloc
对user
和pwd
来说可能不是一个好主意。
这是因为 prompts
将获得包含在 user
和 pwd
对象中的内存地址的副本:它将指向相同的内存区域,但不会指向 Smalltalk对象...
gcMalloc 只监控 Smalltalk 对象的垃圾回收。因此,如果不再使用 Smalltalk 对象,尽管其他一些对象指向同一个 C 堆,但 C 堆可能会过早地被释放......
示例:
fillPrompts
| user pwd prompts |
user := 'User:' copyToHeap: #gcMalloc:.
pwd := 'Password:' copyToHeap: #gcMalloc:.
prompts := CIntegerType char pointerType gcMalloc: 2.
prompts at: 0 put: user.
prompts at: 1 put: pwd.
^prompts
copyToHeap:
创建一个 CPointer 对象。只要该方法处于活动状态,它的上下文就会指向这些对象(通过堆栈上的插槽)。
但是这个方法返回后,没有任何对象指向CPointer对象。
如果发生了一些垃圾回收,它们关联的指向 C 堆的指针将被释放。
但是 prompts
仍然包含对已释放内存的引用(所谓的悬空指针)。
DLLCC 与 C 非常接近,必须像编写 C 代码一样小心...而双指针是绝大多数 C 程序员的错误来源。
答案 1 :(得分:2)
你不应该直接处理字节。这在 C 中甚至没有意义。
#gcCalloc
或 #gcCopyToHeap
以便在仍自动释放的堆上分配内存。通常,使用这些方法是安全的,因为您只需要在单个方法中使用该内存将其传输到 C。假设是 c 函数会复制此内存以备后用。#memberAt:put:
为结构分配成员。