How to map C string with length information?

The following C function of demo.h:

char * demoString();

In demo.zig, after @cImport(@cInclude("demo.h")),
the auto-generated zig function declaration in cmport.zig file will be:

pub extern fn demoString() [*c]const u8;

Then, the result string in zig [*c]const u8 will lost the tail sentinel and length information.
Is there a way to keep the string length information without modifying the C code?

I assume [*c] is used because not all char* types are zero terminated.

The good news is the [*c] coerces to all other pointer types, so you can just do:

    const str: []const u8 = demoString();

and the slice len will be correct (apparently a zero terminator is assumed for this coercion).

See https://ziglang.org/documentation/master/#C-Pointers

1 Like

@jumpnbrownweasel Thanks for your reply!

pub fn demoStringCaller() []const u8 {
    const str: []const u8 = demoString();
    return str;
}

I tried this way, but it broke with this error:

error: @bitCast size mismatch: destination type '[]const u8' has 128 bits but source type '[*c]const u8' has 64 bits

And, the error message was marked at the beginning of pub fn demoStringCaller() []const u8.

@i11010520 Sorry for the confusion! This worked for me when I initialized a variable of type [*c]const u8 directly. But it doesn’t work when calling a function that returns [*c]const u8 and I have no idea why.

Anyway, calling sliceTo does work, as follows:

    const S = struct {
        pub fn demoString() [*c]const u8 {
            const str: []const u8  = "asdf";
            return str.ptr;
        }
    };
    const z_str: []const u8 = std.mem.sliceTo(S.demoString(), 0);
    try expectEqual(z_str.len, 4);

So it looks like you have to call sliceTo, which is not as nice, sorry about that, I should have tried it with a function call.

The following does work, which is why I said that the coercion would work directly. This is strange to me, but not relevant for your issue.

    const str: []const u8  = "asdf";
    const c_str: [*c]const u8 = str.ptr;
    const z_str: []const u8 = c_str;
    try expectEqual(z_str.len, 4);

Fyi, the following works with the latest 0.10 code, but not with an older release I tried (0.9.0). So I may be stumbling on compiler changes in progress.

@jumpnbrownweasel :+1:Great! std.mem.sliceTo() worked!

false if:

const str: []const u8 = "asdfé"; // 5 char
     const c_str: [*c]const u8 = str.ptr;
     const z_str: []const u8 = c_str;
     try expectEqual(z_str.len, 6); // 6 real len

be careful

@JPL Thanks for your reminding!
Yes, after defining const str: []const u8 = "asdfé", the str.len is also 6.
Because .len is length of u8, not length of glyph.

1 Like

Hello,
I made a module to know the number of characters that supports Unicode for an area: “ const u8”
https://github.com/AS400JPLPC/zig_TermCurs/blob/master/deps/curse/utils.zig


var iterx = utl.iteratS.iterator(string);
                        while (iterx.next()) |_| {
                            //try stdout.writer().print("\n\r iter outils => {s}\n\r",.{ch});
                            wl += 1 ;  // nbr char
                        }