Let’s say I want to create a wrapper for printf( char *fmt, ... ). How do I convert map char * to a crystal type? The manual doesn’t mention strings under the C bindings topic as far as I see.
And does crystal support varargs, either native ones to use within crystal code or C ones to use with bindings?
See the source code for Crystal’s standard library.
Then
s = "I am a string."
LibC.printf(s)
To use string pointers with Crystal
@[Link("curl")]
lib Curl
# Any of them will work.
# fun curl_version : LibC::Char*
# fun curl_version : UInt8*
# fun curl_version : Pointer(LibC::Char)
fun curl_version : Pointer(UInt8)
end
puts String.new(Curl.curl_version)
If a type defines a to_unsafe method, when passing it to C the value returned by this method will be passed.
For example, the String class implements to_unsafe to return UInt8*:
lib C
fun printf(format : UInt8*, ...) : Int32
end
a = 1
b = 2
C.printf "%d + %d = %d\n", a, b, a + b
C.printf "Static Text\n"
I tried to use str.as(UInt8*) to get the string as an array of UInt8 but while this is fine with the original prelude, it triggers a bug when I try to do this with my own minimal prelude.
crystal build --prelude ./prelude.cr obj.cr
Module validation failed: Function return type does not match operand type of return inst!
ret i32 %0, !dbg !28
i64 (Exception)
from crystal in ‘??’
from crystal in ‘??’
from crystal in ‘??’
from crystal in ‘??’
from crystal in ‘??’
from crystal in ‘__crystal_main’
from crystal in ‘??’
from crystal in ‘main’
from /usr/lib/libc.so.6 in ‘??’
from /usr/lib/libc.so.6 in ‘__libc_start_main’
from crystal in ‘_start’
from ???
Error: you’ve found a bug in the Crystal compiler. Please open an issue, including source code that will allow us to reproduce the bug: GitHub · Where software is built
I guess I need to use a (different) type declaration somewhere but it isn’t obvious to me where.
to_unsafe needs to be written first without the prelude and when I try to write a wrapper it seems to just return the same string as String.
Got it. I’ve bookmarked an old projects — lilith and crystal-kernel — in case I decide to write my own personal prelude someday.
For further reading or inspiration, you might also find the Crystal source for String interesting: string.cr.
Confirmed that the following code works with crystal build --prelude empty
@[Link("c")]
lib LibC
fun printf(format : UInt8*, ...) : Int32
end
# Open class or Monkey Patch for Ruby / Crystal
class String
def to_unsafe : UInt8*
pointerof(@c)
end
end
str = "str"
LibC.printf(str)