# C-binding type signature for pointer or nil

**URL:** <https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637>\
**Category:** Help & Support\
**Created:** [January 6, 2026, 4:43pm UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637 "2026-01-06T16:43:02Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![SleepingInsomniac](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/sleepinginsomniac/32/1442_2.png) [@SleepingInsomniac](https://forum.crystal-lang.org/u/SleepingInsomniac)\
**Post date:** [January 6, 2026, 4:43pm UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/1 "2026-01-06T16:43:02Z")

</div>

Hi, I’ve been working on bindings for SDL3: [GitHub - SleepingInsomniac/sdl3.cr: SDL3 bindings for crystal](https://github.com/SleepingInsomniac/sdl3.cr).

There’s a type signature that accepts a pointer to a c-struct in the renderer bindings:

```crystal
# extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect);
fun render_texture = SDL_RenderTexture(renderer : Renderer*, texture : Texture*, srcrect : FRect*, dstrect : FRect*) : Bool

```

SDL3’s documentation states that the rect arguments are: “a pointer to the source rectangle, or NULL for the entire ….”

I can’t use `: FRect*?` or crystal gives an error about only using primitive types.

I’m calling this lib function from my crystal adapter code:

```crystal
    def render_texture(texture : Texture, source_rect : FRect? = nil, dest_rect : FRect? = nil)
      sr = source_rect.try { |sr| pointerof(sr) } || Pointer(FRect).null
      dr = dest_rect.try { |dr| pointerof(dr) } || Pointer(FRect).null
      LibSdl3.render_texture(@pointer, texture, sr, dr)
    end

```

Which works, but if I pass the rects directly, I get type errors. For objects like my texture object the c-bindings call `#to_unsafe`. I would have expected something similar for the c-struct that’s being passed in.

Is there a better way to handle a this?

---

<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:** [January 6, 2026, 5:13pm UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/2 "2026-01-06T17:13:15Z")

</div>

Could you clarify what kind of type error you get for which specific call?

---

<div class="post-metadata">

**Author:** ![SleepingInsomniac](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/sleepinginsomniac/32/1442_2.png) [@SleepingInsomniac](https://forum.crystal-lang.org/u/SleepingInsomniac)\
**Post date:** [January 6, 2026, 5:26pm UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/3 "2026-01-06T17:26:52Z")

</div>

For example, with a type signature like this:

```auto
class Renderer
  # ...
    def render_texture(texture : Texture, source_rect : FRect? = nil, dest_rect : FRect? = nil)
      LibSdl3.render_texture(@pointer, texture, source_rect, dest_rect)
    end

```

Calling

```auto
    renderer.render_texture(texture, nil, Sdl3::FRect.new(x: 0, y: y_offset, w: width, h: height))

```

raises a type error:

```auto
Error: argument 'dstrect' of 'LibSdl3#render_texture' must be Pointer(LibSdl3::FRect), not LibSdl3::FRect

```

And if I add pointerof:

```auto
 278 | LibSdl3.render_texture(@pointer, texture, pointerof(source_rect), pointerof(dest_rect))
                                                 ^
Error: argument 'srcrect' of 'LibSdl3#render_texture' must be Pointer(LibSdl3::FRect), not Pointer(Nil)

```

---

<div class="post-metadata">

**Author:** ![yxhuvud](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/yxhuvud/32/27_2.png) [@yxhuvud](https://forum.crystal-lang.org/u/yxhuvud)\
**Post date:** [January 6, 2026, 9:29pm UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/4 "2026-01-06T21:29:53Z")

</div>

> [@SleepingInsomniac](#):
>
> I can’t use `: FRect*?` or crystal gives an error about only using primitive types.

Yes. Note that `FRect*` already accepts null pointers, ie `Pointer(FRect).null` is acceptable. So just remove the `?` and it should work.

---

<div class="post-metadata">

**Author:** ![SleepingInsomniac](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/sleepinginsomniac/32/1442_2.png) [@SleepingInsomniac](https://forum.crystal-lang.org/u/SleepingInsomniac)\
**Post date:** [January 6, 2026, 10:47pm UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/5 "2026-01-06T22:47:07Z")

</div>

Yes, that’s the solution I outlined above. I guess my post was more just asking about language ergonomics. That is, if a lib function expects a pointer to a c struct, passing a struct to that method seems like it should automatically convert to a pointer of the type (in the nil case, `Pointer(FRect).null`)

---

<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:** [January 7, 2026, 12:46am UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/6 "2026-01-07T00:46:47Z")

</div>

When creating large-scale bindings, consider defining a wrapper class (value object) in Crystal. This class represents the corresponding C struct. With this design, users work only with Crystal types. This makes implicit conversion between values and pointers easy. If designed properly, users will find it safe and easy to use.

However, this approach adds complexity. You need to carefully consider who allocates the memory. You must decide whether the Crystal class holds a pointer to the struct or holds the struct value itself. You need to clearly distinguish between these cases:

- When the struct is allocated on the C side and Crystal only holds a pointer
- When Crystal allocates memory and holds the struct value
- When both cases are mixed

You also need to consider how to free memory. For example, whether you can use finalize, or whether you should use RAII with blocks.

Therefore, use this approach only when you want to provide high-quality bindings for end users. Crystal users are smart, so it’s also fine to provide only low-level bindings and let them handle memory management themselves.

---

<div class="post-metadata">

**Author:** ![SleepingInsomniac](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/sleepinginsomniac/32/1442_2.png) [@SleepingInsomniac](https://forum.crystal-lang.org/u/SleepingInsomniac)\
**Post date:** [January 7, 2026, 1:39am UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/7 "2026-01-07T01:39:33Z")

</div>

I hate to ask, but is this response ai generated? If you look at the source, I have plenty of wrapper classes defined that interact with the lib functions, and in fact the question is about a wrapper class method interacting with a lib function.

---

<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:** [January 7, 2026, 1:49am UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/8 "2026-01-07T01:49:00Z")

</div>

Half yes, half no. While the text is indeed generated by AI, I first write the response in Japanese, then have Claude proofread and translate it into English. So the content itself is human-made.

And your wrapper class method appeared to take a C-compatible structure as an argument directly.

P.S.:  
I found that you’re building many interesting Crystal libraries.  
From now on, before replying on reflex, I’ll check the asker’s project first.

---

<div class="post-metadata">

**Author:** ![ysbaddaden](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ysbaddaden/32/2252_2.png) [@ysbaddaden](https://forum.crystal-lang.org/u/ysbaddaden)\
**Post date:** [January 7, 2026, 3:08pm UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/9 "2026-01-07T15:08:59Z")

</div>

There’s little you can do. We **must take a reference** to the struct, otherwise the struct is **passed by value**. This is identical to C:

```c
SDL_FPRect src = { .x = 0, .y = 0, .w = 10, .h = 10 };
SDL_RenderTexture(renderer, texture, &src, NULL);

```

Then in Crystal:

```crystal
src = LibSDL3::FPRect.new(x: 0, y: 0, w: 10, h: 10)
LibSDL3::RenderTexture(renderer, texture, pointerof(src), nil)

```

If the value is nilable… you must transform it into a `Pointer(Rect).null` manually or you’ll end up with an invalid pointer such as `Pointer(Nil)` or `Pointer(Rect | Nil)` and neither will be the expected memory address or layout.

Yes, this is boring and tedious.

The only alternative I can fathom are method overloads to let the compiler do its job. That may be just as tedious to write:

```crystal
def render_texture(texture, src : Rect, dst : Rect)
  LibSDL3::RenderTexture(self, texture, pointerof(src), pointerof(dst))
end

def render_texture(texture, src : Rect, dst : Nil)
  LibSDL3::RenderTexture(self, texture, pointerof(src), nil)
end

def render_texture(texture, src : Nil, dst : Rect)
  LibSDL3::RenderTexture(self, texture, nil, pointerof(dst))
end

def render_texture(texture, src : Nil, dst : Nil)
  LibSDL3::RenderTexture(self, texture, nil, nil)
end

```

---

<div class="post-metadata">

**Author:** ![SleepingInsomniac](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/sleepinginsomniac/32/1442_2.png) [@SleepingInsomniac](https://forum.crystal-lang.org/u/SleepingInsomniac)\
**Post date:** [January 7, 2026, 3:28pm UTC](https://forum.crystal-lang.org/t/c-binding-type-signature-for-pointer-or-nil/8637/10 "2026-01-07T15:28:34Z")

</div>

Thanks, I actually did have them all implemented as overloads initially. It does seem like the better approach, albeit tedious like you mentioned.
