2

我应该如何创建一个 (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.

一个 64 位数组也是如此prompts,其中前 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.
4

2 回答 2

2

DLLCC 提供了一些非常接近 C 的 API。您需要一个包含两个字符指针的数组。

prompts := CIntegerType char pointerType gcMalloc: 2.

然后你可以像这样填充这个数组:

prompts at: 0 put: user.
prompts at: 1 put: pwd.

请注意,索引模仿 C like prompts[0]=user; prompts[1]=pwd;

最后一件事,malloc你必须做的一切free,否则你会得到内存泄漏。

这意味着您应该更好地保护所有这些代码

["your protected code here"]
    ensure: [prompts free. user free. pwd free]`

……或者更糟……

["your protected code here"]
    ensure:
        [prompts isNil ifFalse: [prompts free].
        "etc..."]`.

在早期的开发中,我建议你最好使用gcMallocgcMalloc:.

经过思考

gcMallocuser对于and来说可能不是一个好主意pwd

这是因为prompts将获得包含在userpwd对象中的内存地址的副本:它将指向相同的内存区域,但不会指向 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 程序员的错误来源。

于 2021-02-20T08:27:26.470 回答
2

您不应该直接处理字节。这在 C 中甚至没有意义。

  1. 使用两个 char* 成员创建一个结构,这更易于声明、创建和处理。
  2. 使用#gcCallocor#gcCopyToHeap以便在仍然自动释放的堆上分配内存。通常使用这些方法是安全的,因为您只需要在单个方法中将内存转移到 C 中。假设 c 函数会自行复制该内存以防以后需要它。
  3. 您可以使用#memberAt:put:将成员分配给结构。
于 2021-02-20T09:26:46.957 回答