I get some error when I translate a C struct into nim.
I find out the problem and simplify it to following code:
type
Struct* {.packed.} = object
a*: int64
b*: cint
Union* {.union.} = object
s*: Struct
d*: int
echo sizeof(Struct)
echo sizeof(Union)
Compile with nim c -r --cpu:amd64
16
12
$ nim -v
Nim Compiler Version 1.2.0 [Windows: amd64]
Compiled at 2020-04-03
This has also affected my code (I was also using 0.19.0 when last using Nim). Now my DLL code involving variants passed from Delphi can't be used since I need packed unions. Is this going to be changed back to the earlier behaviour?
type
Struct* {.packed.} = object
a*: int64
b*: cint
# Union* {.union.} = object
Union* {.union, packed.} = object
s*: Struct
d*: int
echo sizeof(Struct)
echo sizeof(Union)
{.union, packed.} was allowed until https://github.com/nim-lang/Nim/pull/10780;
right before that PR it gave wrong results:
20
and it gave correct results in 0.19.0
after git bisect, the regression occurred in https://github.com/nim-lang/Nim/pull/9356 which is @krux02 's work rebased + squashed as a single commit; for the original PR that led to this, see https://github.com/nim-lang/Nim/pull/5664 (might give more insight because it has individual commits)
Thanks. This is a showstopper for me using Nim going forward - I'll revert to 0.19.0 and hope that it gets fixed soon.
I tested it and compared it to the c implementation. The outputs 12 and 16 are in fact correct. The member d of type causes an alignment of 8 bytes. This alignment requirement will required padding bytes at the end of Union so that the final size is a multiple of 8.
import macros
macro c_sizeof(a: typed): int32 =
## Bullet proof implementation that works using the sizeof operator
## in the c backend. Assuming of course this implementation is
## correct.
result = quote do:
var res: int32
{.emit: [res, " = sizeof(", `a`, ");"] .}
res
type
Struct* {.packed.} = object
a*: int64
b*: cint
Union* {.union.} = object
s*: Struct
d*: int
echo "sizeof(Struct): ", sizeof(Struct), " expected: ", c_sizeof(Struct)
echo "sizeof(Union): ", sizeof(Union), " expected: ", c_sizeof(Union)
echo "alignof(Struct): ", alignof(Struct)
echo "alignof(Union): ", alignof(Union)
The problem is not about the output of size, is about that the union in nim cannot be packed. A lot of APIs need to pass the correct size of (packed) struct/union to work.
Made a fix on my branch of the compiler https://github.com/krux02/Nim/commit/d0f723f5824d50a49fef9b1f5c13627ef5e0c35e
My Delphi variant interop code is now working again. Thanks all.
Most helpful comment
Made a fix on my branch of the compiler https://github.com/krux02/Nim/commit/d0f723f5824d50a49fef9b1f5c13627ef5e0c35e