Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C interop: expected type bool found c_int #19950

Open
Radvendii opened this issue May 12, 2024 · 6 comments
Open

C interop: expected type bool found c_int #19950

Radvendii opened this issue May 12, 2024 · 6 comments
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. translate-c C to Zig source translation feature (@cImport)
Milestone

Comments

@Radvendii
Copy link

Zig Version

0.13.0-dev.46+3648d7df1

Steps to Reproduce and Observed Behavior

Explanation below, but it's easier to see than explain. I've created a minimal reproduction so you can

git clone https://github.com/Radvendii/zig-scratch
cd zig-scratch
nix develop # or direnv allow
zig build

The error I get

install
└─ install zig-proj
   └─ zig build-exe zig-proj Debug native 1 errors
src/main.zig:11:12: error: expected type 'bool', found 'c_int'
    c.b = c.true;
          ~^~~~~
referenced by:
    callMain: /nix/store/2sngd0f8ary1zgqcx5r6kaf8ab4w37i1-zig-0.13.0-dev.46+3648d7df1/lib/std/start.zig:511:32
    callMainWithArgs: /nix/store/2sngd0f8ary1zgqcx5r6kaf8ab4w37i1-zig-0.13.0-dev.46+3648d7df1/lib/std/start.zig:469:12
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

The issue is with #include <stdbool.h> from c-code, and then referencing values from zig. bool gets mapped to zig bool, but true and false get mapped to c_ints, so a bool defined in c code can't be used as a bool when interfacing with that c code.

In particular, the generated zig code looks like

pub const @"bool" = bool;
pub const @"true" = @as(c_int, 1);
pub const @"false" = @as(c_int, 0);

Expected Behavior

It's tricky. I understand why bool would get mapped to bool, and I understand why #define false 0 in stdbool.h would get translated to a c_int. There's nothing "buggy" about either of those individually. But together they make interfacing with C code that makes use of bools kind of unworkable.

Assigning a c-defined bool to a c-defined bool-type variable seems like it should just work.

@Radvendii Radvendii added the bug Observed behavior contradicts documented or intended behavior label May 12, 2024
@andrewrk andrewrk added translate-c C to Zig source translation feature (@cImport) proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. and removed bug Observed behavior contradicts documented or intended behavior labels May 12, 2024
@andrewrk andrewrk added this to the 1.0.0 milestone May 12, 2024
@Radvendii
Copy link
Author

Thanks for the recatogrization, I wasn't sure if it was a bug or proposal.

I don't know how the tags work, so maybe this is correct anyways, but I didn't invoke zig translate-c at any point, this is just from @cImport() and @cInclude()

@Radvendii
Copy link
Author

I've uncovered even weirder behaviour. In stdbool.h, we have bool defined by #define bool _Bool, so I figured if I overrode this by putting

    @cInclude("stdbool.h");
    @cUndef("bool");
    @cDefine("bool", "int");

To the top of the @cImport() statement i would force zig to define @"bool" = c_int so that the example works,

It doesn't work. Still defines @"bool" = bool. However, wherever bool is used as part of a struct, it now uses c_int.

Totally unsure what's going on now. Is mapping C bool to zig bool hard-coded? Is re-#defineing things not supported?

@Radvendii
Copy link
Author

Okay, it seems indeed that this is a general thing. any time you have

const c = @cImport({
  @cDefine("foo", "1");
  @cUndef("foo");
  @CDefine("foo", "2");
});

It's going to correctly apply the second #define in any C code @cIncluded later on (replacing foo with 2), but if you access that as a variable from zig, it will go with the first definition (c.foo == 1).

I can't tell how much of this is intentional design vs. bugs. #defines don't actually have the same semantics as const declarations, but my intuition is that whatever the last #define declaration is, that one should determine how it shows up in the zig code, since that's how it would show up in C code with the same set of #includes and #defines

@Pyrolistical
Copy link
Contributor

Pyrolistical commented May 12, 2024

More minimal foo.h:

#define bool _Bool
#define true 1
#define false 0

The last 3 lines of zig translate-c foo.h:

pub const @"bool" = bool;
pub const @"true" = @as(c_int, 1);
pub const @"false" = @as(c_int, 0);

@Radvendii
Copy link
Author

I have a pretty janky workaround:

@cImport({
    @cDefine("true", "(_Bool)1");
    @cDefine("false", "(_Bool)0");
    @cInclude("stdbool.h");
    @cUndef("true");
    @cUndef("false");
    @cDefine("true", "(_Bool)1");
    @cDefine("false", "(_Bool)0");
    
    // other @cInclude()s that use stdbool.h...
});

A couple of points of explanation:

  1. We must use (_Bool)1, not (bool)1. The latter confuses zig and it just doesn't understand what the 1 is doing there
  2. We must pre-define as well as post-define true and false. If we only define it before, stdbool.h will override, and if we only define it after, zig will use the first definition (from stdbool.h) to generate its own idea of what true and false are.
  3. We could also just replicate stdbool.h but with altered definitions of true and false if we were so inclined, it's not that long of a file.

@Radvendii
Copy link
Author

It generates

pub const @"true" = @import("std").zig.c_translation.cast(bool, @as(c_int, 1));
pub const @"false" = @import("std").zig.c_translation.cast(bool, @as(c_int, 0));

Which is kind of goofy, but does work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. translate-c C to Zig source translation feature (@cImport)
Projects
None yet
Development

No branches or pull requests

3 participants