Opaque C-Struct needs to be variable and optional (dbus DBusError struct translation failure)

(I am very new to zig and only have a little experience in c)
I am trying to play around with dbus (without bindings) and i am basically trying to translate a C lib-dbus example to zig.
In the example they simply init the DBusError struct via DBusError dbus_error; which is later initialized by dbus_error_init(&dbus_error);
Now when I try to do that in zig

var dbus_error: ?dbus.DBusError = undefined;
dbus.dbus_error_init(&dbus_error);

i get the compile error:

error: opaque type 'cimport.struct_DBusError' cannot be optional
    var dbus_error: ?dbus.DBusError = undefined;

if I make it non optional i get:

error: non-extern variable with opaque type 'cimport.struct_DBusError'
    var dbus_error: dbus.DBusError = undefined;

and if it’s const (which I think it shouldn’t) i get:

error: expected type '?*cimport.struct_DBusError', found '*const cimport.struct_DBusError'
    dbus.dbus_error_init(&dbus_error);



I’ve tried to find a solution for hours now and I am really lost on how to fix this problem

Reference I am following and the DBusError struct documentation

I am not familiar with the dbus API to know what a DBusError is in C, but assuming that it is an opaque pointer (i.e. const DBusError = opaque{};) type in C, your Zig type must be the same: a pointer type that can be null.

It would be likely be ?*dbus.DBusError. It may also safer to initialize it to null and not undefined in this scenario unless you can guaranteed that the C call will modify the value, otherwise it will be undefined behavior.

If it is going to be modified, then it should be var, not const. The constant variant of that type would be ?*const dbus.DBusError.

So I’ve changed it to this:

var dbus_error: ?*dbus.DBusError = null;
dbus.dbus_error_init(dbus_error);

and get the error

dbus[33145]: arguments to dbus_error_init() were incorrect, assertion "error != NULL" failed in file dbus-errors.c line 194.

(dbus_error_init)

replacing it with undefined results in this

General protection exception (no address available)
???:?:?: 0x7fa1e671c899 in ??? (libdbus-1.so.3)
Unwind information for `libdbus-1.so.3:0x7fa1e671c899` was not available, trace may be incomplete

[long nix path]/lib/zig/std/start.zig:524:37: 0x1032820 in main ([name])
            const result = root.main() catch |err| {

From DBus manual:

void dbus_error_init(DBusError *error)
     Initializes a DBusError structure. 

You need to allocate DBusError and call dbus_error_init to initialize the DBusError contents.

// allocate DBusError in stack
var dbus_error: dbus.DBusError = unknown;
// initialize DBusError
dbus.dbus_error_init(&dbus_error);

I just actually looked at the C API, and DBusError it is not an opaque type.

It should be something like this:

const DBusError = extern struct {
    name: [*c]const u8,
    message: [*c]const u8,
    dummy1: c_uint,
    dummy2: c_uint,
    dummy3: c_uint,
    dummy4: c_uint,
    dummy5: c_uint,
    padding: ?*anyopaque,
};

extern fn dbus_error_init(*DBusError) callconv(.c) void;
var dbus_error: dbus.DBusError = undefined;
dbus.dbus_error_init(&dbus_error);

DBusError being opaque confused the heck out of me but after a couple of hours I just kinda accepted it…
Is this a bug of translate-c or did I do something wrong?
also = unknown is an undeclared identifier for me?

I think translate-c gives things the opaque type if the header files given to it didn’t contain the actual type definition, but just mentioned the type in other declarations for example function definitions.

So I think you may be missing some include of a header file that contains the definition of the DBusError struct, within your cInclude.

I think they meant = undefined otherwise I am confused too.

main.zig

const dbus = @cImport({
    @cInclude("dbus/dbus.h");
});

build.zig

exe.linkSystemLibrary("dbus-1");


compiling & running my reference works without issues. I tried including dbus-errors.h in addition to dbus.h which gives me the error

error: "Only <dbus/dbus.h> can be included directly, this file may disappear or change contents."

Have a look at this previous topic (including the other posts in that topic) and see if that helps:

2 Likes

thank you so much <3 (and everybody else who tried to help!)

    var buf: DBusError = undefined;
    const dbus_error: *dbus.DBusError = @ptrCast(&buf);
    dbus.dbus_error_init(dbus_error);

works with

const DBusError = extern struct {
    name: [*c]const u8,
    message: [*c]const u8,
    dummy: isize,
    padding: *opaque {},
};
2 Likes

What version of Zig are you using? I’m running into the same (or similar issue) and this did not solve it for me. I’m getting a segfault.

Nevermind, it was a separate issue. This is working for me as well.

1 Like