[squeak-dev] FFI (Plugin) | Question about multi-dimensional arrays (e.g., char**, int**, void*****...)

Marcel Taeumel marcel.taeumel at hpi.de
Mon Jun 15 13:38:58 UTC 2020

> BTW: "char *libs[n]" doesn't work and won't compile ;)

Hmm... what could the FFI Call spec look like for:

static size_t _sqo_lib_paths(size_t const n, char (*libs[n]))

Maybe like this:

cdeclSqoLibPaths: n with: libs
    <cdecl: size_t '_sqo_lib_paths' (size_t char**)>

Well, calling "self cdeclSqoLibPaths: 0 with: nil" would return the required size n for libs. Then you could construct a byte array with "n * ExternalType size_t byteSize" bytes so that the library can store all the pointers...

n := self cdeclSqoLibPaths: 0 with: nil.
libs := ByteArray new: n * ExternalType size_t byteSize.
self cdeclSqoLibPaths: n with: libs.

Should work. Alternatively, you can use external memory, not Squeak's object memory:

n := self cdeclSqoLibPaths: 0 with: nil.
libs := ExternalAddress allocate: n * ExternalType size_t byteSize.
self cdeclSqoLibPaths: n with: libs.

In both cases, you would need to put it into an object to start reading the data. For example, an ExternalData ... or a fitting ExternalTypeAlias:

data := ExternalData fromHandle: libs type: ExternalType void asPointerType.

Now it get's tricky. At the moment, we cannot tell ExternalData about the "char**" type. So, "data size: n; do: [:each | ... ]" will not work. We can, however, do it manually:

strings := (1 to: n) collect: [:index |
   | data |
   data := libs pointerAt: (index-1 * ExternalAddress wordSize)+1.
   data := ExternalData fromHandle: data type: ExternalType string "char*".
   data fromCString].

libs class == ExternalAddress ifTrue: [libs free].

But then we have to watch out for the pointer sizes on our own.

Maybe we can help here to improve the workflow and avoid redundant code.

Am 15.06.2020 15:00:58 schrieb Tobias Pape <das.linux at gmx.de>:

> On 15.06.2020, at 14:52, Marcel Taeumel wrote:
> > Hello, C99:
> So, "char (*libs[n])" would be equivalent to "char *libs[n]", which is an array of n pointers, each pointing to a character ... which is a null-terminated string, I suppose? Like "char **argv" or "char *argv[]" ... but with n

It is an array of n char-pointers (in fact, C-Strings), and n refers to an earlier variable in the parameter list...

BTW: "char *libs[n]" doesn't work and won't compile ;)

> Best,
> Marcel
>> Am 15.06.2020 14:34:02 schrieb Tobias Pape :
>> > On 15.06.2020, at 14:24, Jakob Reschke wrote:
>> >
>> >
>> > Marcel Taeumel schrieb am Mo., 15. Juni 2020, 13:22:
>> >
>> > - Accept type names such as "int **" or "int[][]" in FFI-call specs and struct-field spec
>> >
>> > One further note: int[][] is not valid C in parameter types. Only the first [] can be without length, and is equivalent to a pointer. So char*argv[] is the same as char**argv. Valid parameter type examples: int a[][3], int b[][2][3]. These are like int(*a)[3] and int(*b)[2][3] if I am not mistaken.
>> >
>> Hello, C99:
>> /* Find all paths that may contain dynamic libraries.
>> * Returns their count. libs may be NULL to get allocation size
>> */
>> static size_t _sqo_lib_paths(size_t const n, char (*libs[n]))
>> {
>> /*...*/
>> }
>> ;)
>> -t

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20200615/a8b97375/attachment.html>

More information about the Squeak-dev mailing list