On Monday, 7 December 2020 at 04:13:16 UTC, Andrew Edwards wrote:
Given:

===============
extern(C):
char*[] hldr;

Why is this extern(C)? A D array ere is probably wrong.

In C, a `char*[] hldr = {...}` is actually represented in D as a static length array, like `char*[1] = [null];`

It should also generally be __gshared if it was declared in C (C defaults to global, D defaults to thread-local), and if declared in C, an additional extern may be required.


So, if you are trying to *link* to C code that has this:

---
// C
char* hldr[] = {0};
---

You'd bind to it in D with

---
// D
extern(C) extern __gshared char*[1] hldr; // matches the C. Make sure the length matches too

// rest for your code the same:
enum I = (1<<0);
struct S { char* ft; char** fm; int f; }

S[] s = [S(cast(char*) "c", &hldr[0])]; // that cast is super iffy though. Should S have `const(char)* ft` instead?

void main(){}
---


In that thing:

extern(C) - tells it it has a C name.
extern - tells it the actual variable is declared externally. This second one makes the linker pull the variable's address from the C code instead of declaring a new variable in D that can be used from C.
__gshared - turn off D's thread local default to match C's global.



Now if you are translating C code to D, that might be different, certainly the second extern is wrong then, and you need to copy over the initial value but the rest still works:

```
// no more second extern, D is now creating a new variable, then it needs to know the value too
extern(C) __gshared char*[1] hldr = [null];

// rest is the same
// including
S[] s = [S(cast(char*) "c", &hldr[0])]; // since it is a gshared static array, this still works
```



But there's a few other contexts that might change this, then you probably do want the static constructor, or maybe you can make some things immutable and make it work that way. All depends on a bit more information than your code gives on its own....

Reply via email to