Создайте 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.

  1. создать структуру с двумя членами типа char*, которую легче объявлять, создавать и обрабатывать.
  2. использовать #gcCalloc или же #gcCopyToHeapчтобы выделить память в куче, которая все еще автоматически освобождается. Как правило, использовать эти методы безопасно, потому что вам нужна только эта память внутри одного метода для передачи ее в C. Предполагается, что c-функция копирует эту память сама на случай, если она понадобится позже.
  3. вы можете использовать #memberAt:put: для назначения членов структуре.
Другие вопросы по тегам