在 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..."]`.
开发初期,建议大家最好使用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 对象。只要该方法处于活动状态,它的上下文就会指向这些对象(通过堆栈上的槽)。
但是在这个方法return之后,没有任何对象指向CPointer对象。
如果发生垃圾收集,它们指向 C 堆的关联指针将被释放。
但是prompts
仍然包含对已释放内存的引用(所谓的悬挂指针)。
DLLCC 与 C 非常接近,必须像编写 C 代码时一样小心...并且双指针是绝大多数 C 程序员的错误来源。
你不应该直接在字节上工作。这在 C 中甚至没有意义。
- 创建一个包含两个 char* 成员的结构,这样更容易声明、创建和处理。
- 使用
#gcCalloc
或 #gcCopyToHeap
以便在仍然自动释放的堆上分配内存。通常使用这些方法是安全的,因为您只需要在单个方法中将内存传输到 C。假设是 c 函数本身复制此内存以备日后需要。
- 您可以使用
#memberAt:put:
将成员分配给结构。
我应该如何创建一个 (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..."]`.
开发初期,建议大家最好使用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 对象。只要该方法处于活动状态,它的上下文就会指向这些对象(通过堆栈上的槽)。
但是在这个方法return之后,没有任何对象指向CPointer对象。
如果发生垃圾收集,它们指向 C 堆的关联指针将被释放。
但是prompts
仍然包含对已释放内存的引用(所谓的悬挂指针)。
DLLCC 与 C 非常接近,必须像编写 C 代码时一样小心...并且双指针是绝大多数 C 程序员的错误来源。
你不应该直接在字节上工作。这在 C 中甚至没有意义。
- 创建一个包含两个 char* 成员的结构,这样更容易声明、创建和处理。
- 使用
#gcCalloc
或#gcCopyToHeap
以便在仍然自动释放的堆上分配内存。通常使用这些方法是安全的,因为您只需要在单个方法中将内存传输到 C。假设是 c 函数本身复制此内存以备日后需要。 - 您可以使用
#memberAt:put:
将成员分配给结构。