Создайте const char ** в образе Visual Works
Как мне создать (const char **), чтобы передать его функции C?
Скажем, мой const char ** назван тогда:
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.
2 ответа
DLLCC предлагает API, очень близкий к C. Вам нужен массив из двух указателей на символы.
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
возможно, не такая уж и хорошая идея для и.
Это потому, что будет получена копия адреса памяти, содержащегося в
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.
Вы не должны работать напрямую с байтами. Это даже не имеет смысла в C.
- создать структуру с двумя членами типа char*, которую легче объявлять, создавать и обрабатывать.
- использовать
#gcCalloc
или же#gcCopyToHeap
чтобы выделить память в куче, которая все еще автоматически освобождается. Как правило, использовать эти методы безопасно, потому что вам нужна только эта память внутри одного метода для передачи ее в C. Предполагается, что c-функция копирует эту память сама на случай, если она понадобится позже. - вы можете использовать
#memberAt:put:
для назначения членов структуре.