How to compare c_short and c_int?

$ zig version
0.13.0

I have a program where at one point I intend to compare a c_short value (stored in a struct) to a c_int value imported from C standard library. Running the code in a debugger shows that both have value 1, but when I do a comparison of whether the values are equal (using ==) it evaluates to false. I already tried casting the c_short into c_int before the comparison (using @as(c_int, my_short)) but that didn’t help either. What am I doing wrong?

The program (call it poll.zig):

const std = @import("std");
const c = @cImport({
    @cInclude("poll.h");
});

pub fn main() void {
    const watchable = c.struct_pollfd{
       .fd = 0, // STDIN
       .events = c.POLLIN,
    };
    var watchables: [1]c.struct_pollfd = .{ watchable };

    const timeout: c_int = 0;

    while (true) {
      const events_count: c_int = c.poll(&watchables, watchables.len, timeout);
      const something_happened: bool = events_count > 0;
      const new_data_readable: bool = watchable.revents == c.POLLIN;
      if (
        something_happened
        and new_data_readable
      ) {
        std.log.info("There's data to be read from STDIN!");
      }
    }
}

The comparison I’m talking about occurs on line 18 (where we assign const new_data_readable: bool).

Similar comparison works fine in the following C program (call it poc.c). See line 21 where we assign int new_data_readable:

#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define FD_READABLE 0

int main() {

  struct pollfd fds_to_watch;
  memset(&fds_to_watch, 0, sizeof(fds_to_watch));
  fds_to_watch.events = POLLIN;
  fds_to_watch.fd = FD_READABLE;

  char buf[64] = {0};

  while (1) {
    int events = poll(&fds_to_watch, 1, 0);

    int something_happened = events > 0;
    int new_data_readable = fds_to_watch.revents & POLLIN;

    if (
      something_happened
      && new_data_readable
    ) {
      int bytes_read = read(FD_READABLE, &buf, sizeof(buf));
      printf("Read %d bytes from standard input\n", bytes_read);
    }
  }

}

I’m not sure if I understood the problem properly. When I tried to compare a c_int and c_short, it worked as intended to me.

const std = @import("std");

const strt = struct {
    val: c_short,
};

test "pub fn main() !void" {
    const val1: strt = .{ .val = 1 };
    const val2: c_int = 1;

    try std.testing.expect(val1.val == val2); // returns true
}

can you share the poll.h file?

also you’re using == operator in zig (line 18) and & operator in C (line 21). Why?

2 Likes

can you share the poll.h file

The poll.h file (/usr/include/poll.h) includes /usr/include/x86_64-linux-gnu/sys/poll.h which includes /usr/include/x86_64-linux-gnu/bits/poll.h which defines (among other things):

/* Event types that can be polled for.  These bits may be set in `events'
   to indicate the interesting event types; they will appear in `revents'
   to indicate the status of the file descriptor.  */
#define POLLIN		0x001		/* There is data to read.  */
#define POLLPRI		0x002		/* There is urgent data to read.  */
#define POLLOUT		0x004		/* Writing now will not block.  */

The function poll seems to be declared in the aforementioned /usr/include/x86_64-linux-gnu/sys/poll.h as:

extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
    __fortified_attr_access (__write_only__, 1, 2);

and in .zig-cache/o/3005576a75d88a99889de11b77437ff0/cimport.zig as

pub extern fn poll(__fds: [*c]struct_pollfd, __nfds: nfds_t, __timeout: c_int) c_int;

you’re using == operator in zig (line 18) and & operator in C (line 21). Why?

No particular reason. Changing the C program to use == comparison or the Zig program to use bitwise-and together with != 0 didn’t help either so that shouldn’t be the issue.


The behavior I described can be seen in VSCode debugger by first building the poll.zig by

zig build-exe -lc poll.zig

and then starting the debugger with config launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "poll demo",
      "type": "lldb",
      "request": "launch",
      "program": "${workspaceFolder}/poll",
      "console": "integratedTerminal"
    },
  ]
}

Setting a breakpoint after the call to c.poll allows us to see that if we’ve typed e.g. asd to the integrated terminal and pressed enter (thus having data readable in the process’ STDIN) events_count is 1 as we expect, watchables[0].revents is…

Ok, I figured it out as I was writing this.

watchables[0].revents is 1 (i.e. == c.POLLIN), but in my program I was trying to access it via watchable.revents (like you could do in C) which for some reason seems to refer to something else than the first watchable in the array of watchables.

I suppose I should study arrays in Zig next…