Arrays in C bindings

258 views
Skip to first unread message

BobTheJanitor

unread,
Jan 4, 2017, 12:21:42 AM1/4/17
to Crystal
I have a c function with the parameters

> int argc
> const char *const *argv

I'm not too fluent in C, but I believe this represents a pointer to an array of strings. But the Crystal Compiler won't let me pass an array, or a pointer of an array

> only primitive types, pointers, structs, unions, enums and tuples are allowed in lib declarations, not Pointer(Array(String)

Please explain what I'm doing wrong.

Tim Uckun

unread,
Jan 4, 2017, 5:10:03 AM1/4/17
to crysta...@googlegroups.com
No it doesn't represent an array of strings. 

Do this.

alias Char = LibC::Char

That's just to save some typing.

When you declare your function do this

fun blah (x : Char*)

Then just pass a string as normal

s="some string"
LibBlah.blah(s)

Crystal will magically call to_unsafe to turn the string into a Char*

If you have an out parameter you will need to cast it to string though so for example

LibBlah.blah(out out_string)

here the c lib created a const char* and you need to make it a string.

s2=String.new(out_string)





--
You received this message because you are subscribed to the Google Groups "Crystal" group.
To unsubscribe from this group and stop receiving emails from it, send an email to crystal-lang+unsubscribe@googlegroups.com.
To post to this group, send email to crysta...@googlegroups.com.
Visit this group at https://groups.google.com/group/crystal-lang.
To view this discussion on the web visit https://groups.google.com/d/msgid/crystal-lang/94046b5c-1358-4133-ab32-76e9310661d4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ary Borenszweig

unread,
Jan 4, 2017, 6:59:54 AM1/4/17
to Crystal
Indeed, `const char *const *argv` is an array of C strings.

Tim Uckun reply would have been correct if just a single `*` appeared on the code, but there are two (so it's a pointer to a pointer).

A C char in Crystal lib is LibC::Char, or just UInt8. Adding two pointers you get LibC::Char**, or UInt8**.

If you have an `Array(String)`, then invoking `to_unsafe` on it (or just passing it to C, which will try to invoke `to_unsafe` for you) will give you something of type `Pointer(String)`, which is not `Pointer(UInt8*)` or `Pointer(Pointer(UInt8))`. This can be done with `map`:

strings.map(&.to_unsafe)

This will make it be `Array(Pointer(UInt8))`, and when invoking `to_unsafe` on that you'll get `Pointer(Pointer(UInt8))`. I don't know a better way of doing that.

Here's some code that compiles:

~~~
lib LibFoo
  fun foo(x : UInt8**)
end

strings = ["foo", "bar", "baz"]
LibFoo.foo(strings.map(&.to_unsafe))
~~~

--
You received this message because you are subscribed to the Google Groups "Crystal" group.
To unsubscribe from this group and stop receiving emails from it, send an email to crystal-lang+unsubscribe@googlegroups.com.
To post to this group, send email to crysta...@googlegroups.com.
Visit this group at https://groups.google.com/group/crystal-lang.
To view this discussion on the web visit https://groups.google.com/d/msgid/crystal-lang/94046b5c-1358-4133-ab32-76e9310661d4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Ary Borenszweig         Manas Technology Solutions
[ar.phone]                      5258.5240       #ARY(279)
[us.phone]                      312.612.1050    #ARY(279)
[email]                         aboren...@manas.com.ar
[web]                           www.manas.com.ar

BobTheJanitor

unread,
Jan 4, 2017, 4:04:44 PM1/4/17
to Crystal
Thank you


On Wednesday, January 4, 2017 at 4:59:54 AM UTC-7, aborenszweig wrote:
Indeed, `const char *const *argv` is an array of C strings.

Tim Uckun reply would have been correct if just a single `*` appeared on the code, but there are two (so it's a pointer to a pointer).

A C char in Crystal lib is LibC::Char, or just UInt8. Adding two pointers you get LibC::Char**, or UInt8**.

If you have an `Array(String)`, then invoking `to_unsafe` on it (or just passing it to C, which will try to invoke `to_unsafe` for you) will give you something of type `Pointer(String)`, which is not `Pointer(UInt8*)` or `Pointer(Pointer(UInt8))`. This can be done with `map`:

strings.map(&.to_unsafe)

This will make it be `Array(Pointer(UInt8))`, and when invoking `to_unsafe` on that you'll get `Pointer(Pointer(UInt8))`. I don't know a better way of doing that.

Here's some code that compiles:

~~~
lib LibFoo
  fun foo(x : UInt8**)
end

strings = ["foo", "bar", "baz"]
LibFoo.foo(strings.map(&.to_unsafe))
~~~
On Wed, Jan 4, 2017 at 2:21 AM, BobTheJanitor <0bobthe...@gmail.com> wrote:
I have a c function with the parameters

> int argc
> const char *const *argv

I'm not too fluent in C, but I believe this represents a pointer to an array of strings. But the Crystal Compiler won't let me pass an array, or a pointer of an array

> only primitive types, pointers, structs, unions, enums and tuples are allowed in lib declarations, not Pointer(Array(String)

Please explain what I'm doing wrong.

--
You received this message because you are subscribed to the Google Groups "Crystal" group.
To unsubscribe from this group and stop receiving emails from it, send an email to crystal-lang...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages