在 Visual Works 图像中创建一个 const char **

Create a const char ** in Visual Works image

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

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

prompts := CIntegerType char pointerType gcMalloc: 2.

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

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

请注意,索引模仿 C,如 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:

事后思考

gcMalloc 对于 userpwd 来说可能不是一个好主意。

这是因为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 对象。只要该方法处于活动状态,它的上下文就会指向这些对象(通过堆栈上的槽)。
但是在这个方法return之后,没有任何对象指向CPointer对象。
如果发生垃圾收集,它们指向 C 堆的关联指针将被释放。

但是prompts仍然包含对已释放内存的引用(所谓的悬挂指针)。

DLLCC 与 C 非常接近,必须像编写 C 代码时一样小心...并且双指针是绝大多数 C 程序员的错误来源。

你不应该直接在字节上工作。这在 C 中甚至没有意义。

  1. 创建一个包含两个 char* 成员的结构,这样更容易声明、创建和处理。
  2. 使用 #gcCalloc#gcCopyToHeap 以便在仍然自动释放的堆上分配内存。通常使用这些方法是安全的,因为您只需要在单个方法中将内存传输到 C。假设是 c 函数本身复制此内存以备日后需要。
  3. 您可以使用 #memberAt:put: 将成员分配给结构。