# How to use C strings from crystal? And varargs

**URL:** <https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035>\
**Category:** Help & Support\
**Created:** [May 3, 2025, 7:42pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035 "2025-05-03T19:42:03Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Alectronic](https://avatars.discourse-cdn.com/v4/letter/a/a6a055/32.png) [@Alectronic](https://forum.crystal-lang.org/u/Alectronic)\
**Post date:** [May 3, 2025, 7:42pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/1 "2025-05-03T19:42:04Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![ralsina](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ralsina/32/2139_2.png) [@ralsina](https://forum.crystal-lang.org/u/ralsina)\
**Post date:** [May 3, 2025, 8:05pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/2 "2025-05-03T20:05:57Z")

</div>

That’s just a `Pointer(LibC::Char)`

And to use it from Crystal, if you know the size:

```auto
String.new(Slice.new(fmt, size))

```

---

<div class="post-metadata">

**Author:** ![Alectronic](https://avatars.discourse-cdn.com/v4/letter/a/a6a055/32.png) [@Alectronic](https://forum.crystal-lang.org/u/Alectronic)\
**Post date:** [May 3, 2025, 8:35pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/3 "2025-05-03T20:35:55Z")

</div>

Thanks for your answer!

In the crystal source code I see LibC::Char as being defined as an alias of UInt8, so leading to the same I had before:

```auto
lib C
    fun printf( format : Pointer(UInt8) )
end

```

But `C.printf "Hi"` results in a fail to compile:` Error: argument ‘format’ of ‘C#printf’ must be Pointer(UInt8), not String.

How can I convert a string into an array of UInt8s?

Edit: I found how to do varargs in Crystal but how to interact with C functions that require varargs?

---

<div class="post-metadata">

**Author:** ![kojix2](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kojix2/32/1583_2.png) [@kojix2](https://forum.crystal-lang.org/u/kojix2)\
**Post date:** [May 3, 2025, 8:49pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/5 "2025-05-03T20:49:26Z")

</div>

See the source code for Crystal’s standard library.

> <https://github.com/crystal-lang/crystal/blob/master/src/lib_c/x86_64-linux-gnu/c/stdio.cr>

Then

```auto
s = "I am a string."
LibC.printf(s)

```

To use string pointers with Crystal

```cr
@[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)

```

---

<div class="post-metadata">

**Author:** ![miry](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/miry/32/1650_2.png) [@miry](https://forum.crystal-lang.org/u/miry)\
**Post date:** [May 3, 2025, 8:52pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/6 "2025-05-03T20:52:53Z")

</div>

I found a nice example in [to\_unsafe - Crystal](https://crystal-lang.org/reference/1.16/syntax_and_semantics/c_bindings/to_unsafe.html)

> 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*`:

```crystal
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"

```

```shell
$ crystal --version
Crystal 1.16.2 (2025-04-29)

LLVM: 20.1.3
Default target: aarch64-apple-darwin24.4.0

$ crystal run libc_example.cr
1 + 2 = 3
Static Text

```

---

<div class="post-metadata">

**Author:** ![Alectronic](https://avatars.discourse-cdn.com/v4/letter/a/a6a055/32.png) [@Alectronic](https://forum.crystal-lang.org/u/Alectronic)\
**Post date:** [May 3, 2025, 9:49pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/7 "2025-05-03T21:49:31Z")

</div>

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](https://github.com/crystal-lang/crystal/issues)

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.

---

<div class="post-metadata">

**Author:** ![miry](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/miry/32/1650_2.png) [@miry](https://forum.crystal-lang.org/u/miry)\
**Post date:** [May 3, 2025, 10:29pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/8 "2025-05-03T22:29:57Z")

</div>

Got it. I’ve bookmarked an old projects — [lilith](https://github.com/ffwff/lilith) and [crystal-kernel](https://github.com/stakach/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](https://github.com/crystal-lang/crystal/blob/master/src/string.cr).

---

<div class="post-metadata">

**Author:** ![ralsina](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ralsina/32/2139_2.png) [@ralsina](https://forum.crystal-lang.org/u/ralsina)\
**Post date:** [May 3, 2025, 10:43pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/9 "2025-05-03T22:43:54Z")

</div>

IIRC: to\_unsafe

---

<div class="post-metadata">

**Author:** ![kojix2](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kojix2/32/1583_2.png) [@kojix2](https://forum.crystal-lang.org/u/kojix2)\
**Post date:** [May 3, 2025, 11:13pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/10 "2025-05-03T23:13:54Z")

</div>

Confirmed that the following code works with `crystal build --prelude empty`

```cr
@[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)

```

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [May 4, 2025, 5:31pm UTC](https://forum.crystal-lang.org/t/how-to-use-c-strings-from-crystal-and-varargs/8035/11 "2025-05-04T17:31:49Z")

</div>

I believe the language reference on `fun` calls should answer your questions: [fun - Crystal](https://crystal-lang.org/reference/1.16/syntax_and_semantics/c_bindings/fun.html)
