Tech News
← Back to articles

Zig / C++ Interop

read original related products more articles

Zig / C++ Interop

Johnny Marler · @johnnymarler · November 11, 2025

Note: this blog post is cross-posted from my personal blog

I’ve been writing Zig and C++ that have to talk to each other. I want both languages to be able to store data types from the other in their own structs/classes.

const c = @cImport ({ @cInclude ( "cppstuff.h" ); }); const MyZigType = struct { foo : c . SharedPtrFoo , };

#include class MyCppType { ZigFoo foo; };

Keep in mind, I don’t want to just define all my Zig types as extern types. I want to use existing types from the standard library and be able to embed those inside my C++ types. I don’t want my choice of programming language to limit where I can put things in memory.

When you want to embed a type, you need its definition, but you don’t actually need the full definition. You just need the size/alignment. That tells the compiler where to offset it into the container type and how much space to reserve for it. In addition, both Zig and C++ can verify type sizes and alignment at compile time. So, we can replace needing the full type definition with a simple macro that provides an opaque type with the same size/alignment, and have the “home language” for that type verify it’s correct at compile time. Here’s such a macro:

#define SIZED_OPAQUE ( name , size , align ) \ typedef struct { \ _Alignas ( align ) unsigned char _[size]; \ } __attribute__(( aligned (align))) name; \ enum { name##Size = size , name##Align = align } // Allows Zig to include fields that store a shared_ptr SIZED_OPAQUE (SharedPtrFoo, 8 , 8 ) // Allows C++ to include fields that store a zig-native Foo struct SIZED_OPAQUE (ZigFoo, 120 , 4 )

And both sides can verify the sizes at compile-time like this:

... continue reading