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