Expected type [*c]cimport.struct_clipboard_opts found cimport.struct_clipboard_opts

Full error:

program.zig:201:51: error: expected type '[*c]C:.Users.SAmar.Desktop.password generator.zig-cache.o.52adec38bfbabd6bb04569bff94a388e.cimport.struct_clipboard_opts', found 'C:.Users.SAmar.Desktop.password generator.zig-cache.o.52adec38bfbabd6bb04569bff94a388e.cimport.struct_clipboard_opts'
    const cb: lcb.clipboard_c = lcb.clipboard_new(opts);
                                                  ^~~~
C:\Users\SAmar\Desktop\password generator\zig-cache\o\52adec38bfbabd6bb04569bff94a388e\cimport.zig:525:42: note: struct declared here
pub const struct_clipboard_opts = extern struct {
                                  ~~~~~~~^~~~~~
C:\Users\SAmar\Desktop\password generator\zig-cache\o\52adec38bfbabd6bb04569bff94a388e\cimport.zig:536:39: note: parameter type declared here
pub extern fn clipboard_new(cb_opts: [*c]clipboard_opts) ?*clipboard_c;

Relevant main code:

const lcb = @cImport({
    @cInclude("libclipboard.h");
});
// ^ (at the top of my file)

pub fn copyToClipboard(text:  []const u8) !void {
    // get length of password as multiple of 4 as lcb.clipboard_opts_x11.transfer_size requests
    var transfer_size: u32 = @intCast(text.len);
    const deltaSize = 4 - (transfer_size % 4);
    if (text.len + deltaSize > @sizeOf(u32)) {
        return ClipboardError.TransferSizeTooLarge;
    }
    transfer_size += deltaSize;

    const opts = lcb.clipboard_opts {
        .win32 = lcb.clipboard_opts_win32 {
            .max_retries = 0, // uses default
            .retry_delay = 0 // uses default
        },
        .x11 = lcb.clipboard_opts_x11 {
            .action_timeout = 5, // 5ms
            .transfer_size = transfer_size, // assuming this is size of data being passed to clipboard
            .display_name = null // uses default
        },
        .user_calloc_fn = null, // uses default
        .user_free_fn = null, // uses default
        .user_malloc_fn = null, // uses default
        .user_realloc_fn = null // uses default
    };
    const cb: lcb.clipboard_c = lcb.clipboard_new(opts);
    defer lcb.clipboard_free(cb);

    if (!lcb.clipboard_set_text_ex(cb, text, text.len, lcb.LCB_CLIPBOARD)) {
        return ClipboardError.ClipboardSetTextFailed;
    }
}

I also include libclipboard.h at the top of my zig program, here is the portion of libclipboard.h that is relevant:

typedef struct clipboard_opts {
    /* I would put the OS specific opts in a union, but anonymous unions are non-standard */
    /* Typing out union names is too much effort */

    /** X11 specific options **/
    struct clipboard_opts_x11 {
        /** Max time (ms) to wait for action to complete **/
        int action_timeout;
        /** Transfer size, in bytes. Must be a multiple of 4. **/
        uint32_t transfer_size;
        /** The name of the X11 display (NULL for default - DISPLAY env. var.) **/
        const char *display_name;
    } x11;

    /** Win32 specific options **/
    struct clipboard_opts_win32 {
        /**
         *  Max number of retries to try to obtain clipboard lock.
         *  If max_retries is zero, the default value will be used.
         *  Specify a negative value for zero retries.
         */
        int max_retries;
        /**
         *  Delay in ms between retries to obtain clipboard lock.
         *  If retry_delay is zero, the default value will be used.
         *  Specify a negative value for no (zero) delay.
         */
        int retry_delay;
    } win32;

    /** User specified malloc (NULL for default) **/
    clipboard_malloc_fn user_malloc_fn;
    /** User specified calloc (NULL for default) **/
    clipboard_calloc_fn user_calloc_fn;
    /** User specified realloc (NULL for default) **/
    clipboard_realloc_fn user_realloc_fn;
    /** User specified free (NULL for default) **/
    clipboard_free_fn user_free_fn;
} clipboard_opts;

/** Opaque data structure for a clipboard context/instance **/
typedef struct clipboard_c clipboard_c;

/**
 *  \brief Instantiates a new clipboard instance of the given type.
 *
 *  \param [in] cb_opts Implementation specific options (optional).
 *  \return The new clipboard instance, or NULL on failure.
 */
LCB_API clipboard_c *LCB_CC clipboard_new(clipboard_opts *cb_opts);

I know it wants me to convert the type to a [*c] but I don’t really know what that means or how to do it (I’m assuming its the pointer reference to the c file but I don’t see how that isn’t what I already have).

Also I am realizing that the clipboard_new() function wants a pointer to the opts but &opts a basically identical error of:

program.zig:201:51: error: expected type '[*c]C:.Users.SAmar.Desktop.password generator.zig-cache.o.52adec38bfbabd6bb04569bff94a388e.cimport.struct_clipboard_opts', found '*const C:.Users.SAmar.Desktop.password generator.zig-cache.o.52adec38bfbabd6bb04569bff94a388e.cimport.struct_clipboard_opts'
    const cb: lcb.clipboard_c = lcb.clipboard_new(&opts);
                                                  ^~~~~
program.zig:201:51: note: cast discards const qualifier
C:\Users\SAmar\Desktop\password generator\zig-cache\o\52adec38bfbabd6bb04569bff94a388e\cimport.zig:536:39: note: parameter type declared here
pub extern fn clipboard_new(cb_opts: [*c]clipboard_opts) ?*clipboard_c;
                                     ~^~~~~~~~~~~~~~~~~

It probably would make sense to define the clipboard_new function to expect a const pointer to cb_opts. Alternatively you could define your opts variable with var instead of const as an easier workaround, but declaring the options pointer const would be the better way.
Either of those should take care of the note: cast discards const qualifier

The next error is that your function returns an optional pointer, but you declare a variable that is a value (not a pointer or optional) and try to initialize it with that returned optional pointer. Instead you can declare an optional pointer instead: const cb: ?*lcb.clipboard_c = lcb.clipboard_new(&opts);

You also can see that type as the return type in:

Another tip would be to write this if you are unsure about a return type:

const cb = lcb.clipboard_new(&opts);
@compileLog(cb); // useful if you are unsure about what you get

This @compileLog is for debugging purposes it will print some output showing you the type and value of a variable, but you will also need to remove it again, because the compiler doesn’t allow you to keep it in code that is compiled into the executable, this is to keep you from leaving debug code in your program without noticing.

Not sure, but maybe you should pass a pointer:

const cb: lcb.clipboard_c = lcb.clipboard_new(&opts);
program.zig:201:51: error: expected type '[*c]cimport.struct_clipboard_opts', found 'cimport.struct_clipboard_opts'
    const cb: lcb.clipboard_c = lcb.clipboard_new(opts);
                                                  ^~~~

The compiler expects a pointer [*c] and you are giving a value.

    const cb: lcb.clipboard_c = lcb.clipboard_new(&opts);
                                                  ^~~~~
program.zig:201:51: note: cast discards const qualifier

Here you have a pointer but it is pointing to something const (read-only), make opts a var to make it writable.

Thank you for explaining all of the factors and adding some tips.

I made some changes:

pub fn copyToClipboard(text:  []const u8) !void {
    // get length of password as multiple of 4 as lcb.clipboard_opts_x11.transfer_size requests
    var transfer_size: u32 = @intCast(text.len);
    const deltaSize = 4 - (transfer_size % 4);
    if (text.len + deltaSize > @sizeOf(u32)) {
        return ClipboardError.TransferSizeTooLarge;
    }
    transfer_size += deltaSize;

    var opts = lcb.clipboard_opts {
        .win32 = lcb.clipboard_opts_win32 {
            .max_retries = 0, // uses default
            .retry_delay = 0 // uses default
        },
        .x11 = lcb.clipboard_opts_x11 {
            .action_timeout = 5, // 5ms
            .transfer_size = transfer_size, // assuming this is size of data being passed to clipboard
            .display_name = null // uses default
        },
        .user_calloc_fn = null, // uses default
        .user_free_fn = null, // uses default
        .user_malloc_fn = null, // uses default
        .user_realloc_fn = null // uses default
    };
    const cb: ?*lcb.clipboard_c = lcb.clipboard_new(&opts);
    defer lcb.clipboard_free(cb);

    if (!lcb.clipboard_set_text_ex(cb, text, text.len, lcb.LCB_CLIPBOARD)) {
        return ClipboardError.ClipboardSetTextFailed;
    }
}

and now I’m getting the error:

program.zig:208:40: error: expected type '[*c]const u8', found '[]const u8'
    if (!lcb.clipboard_set_text_ex(cb, text, text.len, lcb.LCB_CLIPBOARD)) {
                                       ^~~~
C:\Users\SAmar\Desktop\password generator\zig-cache\o\52adec38bfbabd6bb04569bff94a388e\cimport.zig:542:62: note: parameter type declared here
pub extern fn clipboard_set_text_ex(cb: ?*clipboard_c, src: [*c]const u8, length: c_int, mode: clipboard_mode) bool;
                                                            ~^~~~~~~~~~~

I tried just replacing it with &text but that didn’t work either.

Any ideas before I mark your answer as the solution?

text.ptr

[ ]const u8 is a slice that have a pointer ptr and length len
[*]const u8 is a pointer to multiple u8
*const u8 is a pointer to a single u8

1 Like

Instead of:

pub fn copyToClipboard(text:  []const u8) !void {

You probably want: (see the end)

pub fn copyToClipboard(text:  [:0]const u8) !void {

This means that text is a Sentinel-Terminated Slice, a slice is a pointer + a length, the pointer points to the start of some memory that can be thought of as an array of elements of type u8 in this case and the length tells us how long that array is. Because it is sentinel terminated we have the sentinel a zero byte at pointer[length].

However c doesn’t use slices, c uses just the pointer and then knows where the text ends by looking for the zero byte. We can access the pointer by using text.ptr and convert it to the [*c]const u8 type by using this:

if (!lcb.clipboard_set_text_ex(cb, text.ptr, text.len, lcb.LCB_CLIPBOARD)) {

The important thing here is that text.ptr actually points to a zero terminated area in memory. Zig’s string constant literals are always zero terminated, but if you create strings at run time and you need to pass those to c then look for functions ending with a capital Z like allocator.dupeZ and std.fmt.allocPrintZ those create slices that point to memory that is zero terminated thus you can savely pass those as strings to c.

*Oh I just now see that clipboard_set_text_ex takes text.len so you are probably fine with using:

pub fn copyToClipboard(text:  []const u8) !void {

In this case, because the c api actually takes a length of the string (which is relatively uncommon in c).

1 Like

Thank you. I just ended up using text.ptr and it worked.

1 Like

See also Documentation - The Zig Programming Language.

Unfortunately the documentation lacks examples.

Discourse formats as a checkbox like this , so its better to use []const u8

2 Likes

thank you
it was an actual check box

1 Like