Search code examples
bindingwrapperffinim-langpragma-pack

Nim: How to wrap a c struct that contains bitfields?


The question is if I see a bitfield in a c struct as such:

struct Example
{
    int A;
    int B;
    int C : 3;
    int D : 3;
    int E : 3;
    int F : 8;
    bool G : 1;
    bool H : 1;
};

Would the correct binding in Nim be as such?

type Example {.packed, importc: "Example", "example.h".} = object
  a {.importc: "a".} : int32
  b {.importc: "b".} : int32
  c {.bitsize: 3, importc: "c".} : int32
  d {.bitsize: 3, importc: "d".} : int32
  e {.bitsize: 3, importc: "e".} : int32
  f {.bitsize: 8, importc: "f".} : int32
  g {.bitsize: 1, importc: "g".} : bool
  h {.bitsize: 1, importc: "h".} : bool

or as such?

type Example {.importc: "Example", "example.h".} = object
  a {.importc: "a".} : int32
  b {.importc: "b".} : int32
  c {.importc: "c".} : int32
  d {.importc: "d".} : int32
  e {.importc: "e".} : int32
  f {.importc: "f".} : int32
  g {.importc: "g".} : bool
  h {.importc: "h".} : bool

Does the {.packed.} pragma align on the byte? Is the {.packed.} pragma even required here because I am importing from C?


Solution

  • The correctest binding is:

    type Example {.importc: "struct Example",header:"example.h".} = object
      A: cint
      B: cint
      C{.bitsize:3.}: cint
      D{.bitsize:3.}: cint
      E{.bitsize:3.}: cint
      F{.bitsize:8.}: cint
      G{.bitsize:1.}: bool
      H{.bitsize:1.}: bool
    

    note struct Example because you said it was a C struct. If you intend to compile with nim cpp you can use the above, importc:"Example" or just importc with no argument

    and yes, if you know your target machine's ints are 32bits, int32 is much more convenient and is what i would use.

    {.packed.} is not what you want, it is the equivalent of

    struct __attribute__((__packed__)) Example {
      ...
    }
    

    and using it results in a struct that is 11 bytes instead of 12

    you don't need to individually {.importc.} each member, unless you want to change its name, i.e.

    type Example{.importc:"struct Example",header:"example.h".} = object
      a{.importc:"A".}: cint
      b{.importc:"B".}: cint
      c{.importc:"C",bitsize:3.}: cint
      ...