Creating array of structs being used in C interface
Adam D. Ruppe via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sun Nov 27 05:54:54 PST 2016
On Sunday, 27 November 2016 at 12:59:32 UTC, Timoses wrote:
> Why is it a linker problem? I'm not linking to the c interface
> but merely using D structs...
It is a linker problem because you didn't link to it... D structs
have an initializer, even if they are used for interfacing with
C. This is a small blob of data called something like
`_D10neo4jTypes17neo4j_map_entry_t6__initZ`, or can be all
zeroes, and is generated with the interface module.
So if you use the initializer from the interface module, but do
not link it in, you get an undefined symbol.
Easiest fix: just link in that .d file and use the automatic
features.
Why does your struct have an initializer data symbol instead of
being all zeroes? I'm not entirely sure, but I think it is
because the contents are structs and it didn't look inside those
structs to see if they too are zeroes, it just assumed struct =
fancy initialized. That's arguably an enhancement request, but I
wouldn't call it a bug.
You can often bypass the initializer by using `=0` or `=void` in
definitions, but not here... and that is arguably a bug, if you
`=void` all fields, it should be free to zero initialize the
whole thing, but it doesn't.
Why do you use the initializer? Look at each of these lines:
neo4j_map_entry_t[] mapa2; // yes
neo4j_map_entry_t entry1 = { key: neo4j_string("prop1"),
value: neo4j_string("testprop1")}; // yes
neo4j_map_entry_t entry2 = { key: neo4j_string("prop2"),
value: neo4j_string("testprop2")}; // yes
neo4j_map_entry_t* mapp; // yes
Those work because nothing is default initialized: pointers and
arrays start as null (and thus point to no actual struct data).
The middle lines have you explicitly initializing it, so again,
no default needed.
// These don't
neo4j_map_entry_t[2] mapa1; // no
This is basically the same as `neo4j_map_entry_y a;` done twice -
you create a struct, which is default initialized, which
references that data.
You can bypass this with `=void` at the end of that line.
mapa2.length = 2; // no
This also default initializes the new items you add. Just don't
use that length function if you don't want to link in the other
.d file.
mapa2 ~= entry1; // no
I think the implementation does length += 1, then copy arr[$-1] =
entry1, so there's a temporary default in there.
There's arguably a better implementation possible so this one
*could* work. But if it doesn't now, just avoid that function
(try something like std.array.uninitializedArray perhaps).
neo4j_map_entry_t[] mapa3 = [{ key: neo4j_null, value:
neo4j_null}]; // no
And I don't know with this one, since I don't know what
neo4j_null is. Perhaps you just didn't do the extern symbol
right, or perhaps it too is a little data blob that should be
linked in.
But while this can be annoying, it isn't really a bug - it is D's
auto initialize feature creating some data that you didn't link.
Avoiding D-specific features and bypassing initialization with
=void can skip it, but I recommend just linking in the module.
More information about the Digitalmars-d-learn
mailing list