Re: Can not get struct member addresses at compile time
On 6/16/21 3:27 PM, Doeme wrote: On Wednesday, 16 June 2021 at 22:16:54 UTC, H. S. Teoh wrote: The compiler does not (and cannot) know. But the runtime dynamic linker can, and does. The two are bridged by the compiler emitting a relocatable symbol for the address of the global variable, with a table of relocations (offsets in the code) that the runtime linker patches the actual addresses into when the program is executed. T Exactly! Except that the dynamic linker is not really involved here, since all the symbols can/must be relocated statically at link time. Thank you, both. It still rules out an address at "compile time" in general. For example, we cannot use such an address when instantiating a template, or static array length, etc. And if I understand it correctly, there must be a pointer *variable* for the linker to initialize. Fine then: That's how this usage works for C but not for D. :) Thank you, Ali
Re: Struct assignment fails, why?
On Wednesday, 16 June 2021 at 20:54:07 UTC, H. S. Teoh wrote: On Wed, Jun 16, 2021 at 08:44:46PM +, Brian via Digitalmars-d-learn wrote: [...] struct item { string name; int type; }; [...] new_item = { "item1", 1 }; The {...} initializer syntax is only available in variable declarations, e.g.: item i = { "item1", 1 }; You cannot use this syntax in assignment statements. A simple alternative is to use constructor syntax for constructing an instance of the struct: new_item = item("item", 1); T Gotcha. Thanks. ~Brian
Re: Can not get struct member addresses at compile time
On Wednesday, 16 June 2021 at 22:16:54 UTC, H. S. Teoh wrote: The compiler does not (and cannot) know. But the runtime dynamic linker can, and does. The two are bridged by the compiler emitting a relocatable symbol for the address of the global variable, with a table of relocations (offsets in the code) that the runtime linker patches the actual addresses into when the program is executed. T Exactly! Except that the dynamic linker is not really involved here, since all the symbols can/must be relocated statically at link time.
Re: Can not get struct member addresses at compile time
On Wed, Jun 16, 2021 at 02:42:41PM -0700, Ali Çehreli via Digitalmars-d-learn wrote: [...] > Actually, it is news to me that the compiler can know (determine?) the > address of a global variable. [...] The compiler does not (and cannot) know. But the runtime dynamic linker can, and does. The two are bridged by the compiler emitting a relocatable symbol for the address of the global variable, with a table of relocations (offsets in the code) that the runtime linker patches the actual addresses into when the program is executed. T -- War doesn't prove who's right, just who's left. -- BSD Games' Fortune
Re: Can not get struct member addresses at compile time
On Wednesday, 16 June 2021 at 21:42:41 UTC, Ali Çehreli wrote: On 6/16/21 8:47 AM, Doeme wrote: > On Wednesday, 16 June 2021 at 13:36:07 UTC, Ali Çehreli wrote: >> On 6/16/21 2:27 AM, Doeme wrote: >> >> > How does one get the address of a struct member? >> >> Here is an experiment with offsetof and opDispatch: > > Cool stuff! > I actually tried a very similar approach once, but it did not work out, > since the D compilers refuse to do pointer arithmetic at compile time :/ > > ```d > struct Foo{ > ubyte bar; > } > > void* membaddr(void *ptr, ulong offset){ > return ptr+offset; > } > > __gshared Foo foo; > void* bar = membaddr(, foo.bar.offsetof); > //Error: cannot perform arithmetic on `void*` pointers at compile time > ``` > > I guess that the opDispatch-method will suffer from the same issue... No, opDispatch does not work either for compile time addresses. Actually, it is news to me that the compiler can know (determine?) the address of a global variable. I thought the loador would determine the addresses, but apparently not. Is it really a constant compiled value in the case of C? Can you show an example please? Ali The compiler can, in deed, not know the address, but the linker can. Example: ```c #include struct Foo{ int bar; int baz; }; struct Foo foo; static const void *fooptr = static const void *barptr = static const void *bazptr = int main(int argc, char **argv){ printf("Address of foo: %p\n", fooptr); //Address of foo: 0x55fbd8292030 printf("Address of bar: %p\n", barptr); //Address of bar: 0x55fbd8292030 printf("Address of bau: %p\n", bazptr); //Address of bau: 0x55fbd8292034 return 0; } ``` We can see that the code actually outputs the right addresses. If we investigate the object file passed down to the linker, we see: ``` $ gcc -c test.c $ objdump -x test.o [...] SYMBOL TABLE: ldf *ABS* test.c ld .text .text ld .data.rel.local .data.rel.local l O .data.rel.local0008 fooptr 0008 l O .data.rel.local0008 barptr 0010 l O .data.rel.local0008 bazptr ld .rodata .rodata g O .bss 0008 foo g F .text 0070 main *UND* _GLOBAL_OFFSET_TABLE_ *UND* printf [...] RELOCATION RECORDS FOR [.data.rel.local]: OFFSET TYPE VALUE R_X86_64_64 foo 0008 R_X86_64_64 foo 0010 R_X86_64_64 foo+0x0004 [...] ``` This tells us that: * There are 3 variables in the initialized .data.rel.local section, our pointers. * There is one variable in the zeroed .bss section, our instance of struct Foo * To the positions of the of our three pointers in the .data.rel.local section, there is being written the address of the symbol foo, foo, and lastly, foo+4. Thus, the address is only known at link time, but it _can_ be known by placing the right relocation commands to the object elf-file (i.e. relocation + offset, foo+4).
Re: Can not get struct member addresses at compile time
On 6/16/21 8:47 AM, Doeme wrote: > On Wednesday, 16 June 2021 at 13:36:07 UTC, Ali Çehreli wrote: >> On 6/16/21 2:27 AM, Doeme wrote: >> >> > How does one get the address of a struct member? >> >> Here is an experiment with offsetof and opDispatch: > > Cool stuff! > I actually tried a very similar approach once, but it did not work out, > since the D compilers refuse to do pointer arithmetic at compile time :/ > > ```d > struct Foo{ > ubyte bar; > } > > void* membaddr(void *ptr, ulong offset){ > return ptr+offset; > } > > __gshared Foo foo; > void* bar = membaddr(, foo.bar.offsetof); > //Error: cannot perform arithmetic on `void*` pointers at compile time > ``` > > I guess that the opDispatch-method will suffer from the same issue... No, opDispatch does not work either for compile time addresses. Actually, it is news to me that the compiler can know (determine?) the address of a global variable. I thought the loador would determine the addresses, but apparently not. Is it really a constant compiled value in the case of C? Can you show an example please? Ali
Re: Struct assignment fails, why?
On Wed, Jun 16, 2021 at 08:44:46PM +, Brian via Digitalmars-d-learn wrote: [...] > struct item > { > string name; > int type; > }; [...] > new_item = { "item1", 1 }; The {...} initializer syntax is only available in variable declarations, e.g.: item i = { "item1", 1 }; You cannot use this syntax in assignment statements. A simple alternative is to use constructor syntax for constructing an instance of the struct: new_item = item("item", 1); T -- Everybody talks about it, but nobody does anything about it! -- Mark Twain
Re: Internal Server Error on reload of dfeed.js
On Wednesday, 16 June 2021 at 06:28:40 UTC, guest wrote: STR: 1. open http://forum.dlang.org/static-bundle/637528586548394375/dlang.org/js/dlang.js+js/dfeed.js 2. press reload (F5 or ctrl+R) Noticed this too and fixed it a bit ago. It was sending 500 instead of 304, so actually the only way you could see it was to press F5 (but not Ctrl+F5).
Struct assignment fails, why?
Hello all -- I have a question about assigning to structs. I want to be able to create an array of structs that may contain different contents depending on user input. I have reduced the test case down. The following fails to compile: ```d import std.stdio; struct item { string name; int type; }; item[] items; void main(string[] args) { item new_item; for (int i = 0; i < args.length; i++) { if (args[i] == "item1") { new_item = { "item1", 1 }; } else if (args[i] == "item2") { new_item = { "item2", 2 }; } else { new_item = { "item3", 3 }; } items ~= new_item; } for (int i = 0; i < items.length; i++) writeln(items[i].name); } ``` This fails (dmd 2.097) with the following: ```d struct_bad.d(17): Error: found `}` when expecting `;` following statement struct_bad.d(17): Deprecation: use `{ }` for an empty statement, not `;` struct_bad.d(18): Error: found `else` when expecting `;` following statement struct_bad.d(19): Error: found `}` when expecting `;` following statement struct_bad.d(19): Deprecation: use `{ }` for an empty statement, not `;` struct_bad.d(20): Error: found `else` when expecting `;` following statement struct_bad.d(21): Error: found `}` when expecting `;` following statement struct_bad.d(21): Deprecation: use `{ }` for an empty statement, not `;` struct_bad.d(24): Error: found `items` when expecting `;` following statement struct_bad.d(24): Error: found `~=` instead of statement struct_bad.d(30): Error: found `End of File` when expecting `}` following compound statement struct_bad.d(30): Error: found `End of File` when expecting `}` following compound statement struct_bad.d(30): Error: found `End of File` when expecting `}` following compound statement ``` However, a slight tweak allows the code to compile and work correctly. ```d import std.stdio; struct item { string name; int type; }; item[] items; void main(string[] args) { for (int i = 0; i < args.length; i++) { if (args[i] == "item1") { item new_item = { "item1", 1 }; items ~= new_item; } else if (args[i] == "item2") { item new_item = { "item2", 2 }; items ~= new_item; } else { item new_item = { "item3", 3 }; items ~= new_item; } } for (int i = 0; i < items.length; i++) writeln(items[i].name); } ``` I guess I am unclear as to why the first fails and the second succeeds. TIA. ~Brian
Re: How to translate this C macro to D mixin/template mixin?
On Wednesday, 16 June 2021 at 05:48:21 UTC, VitaliiY wrote: On Tuesday, 15 June 2021 at 12:39:40 UTC, Dennis wrote: On Tuesday, 15 June 2021 at 12:18:26 UTC, VitaliiY wrote: [...] ```D enum string ADDBITS(string a, string b) = ` { bitbuffer = (bitbuffer<<(`~a~`))|((`~b~`)&((1<<`~a~`)-1)); numbits += (`~a~`); mixin(STOREBITS); }`; // on use: ADDBITS(varA, varB) becomes mixin(ADDBITS!("varA", "varB")); ` [...] Thank you, Dennis. I tried with this kind of mixin, but a, b - are type of 'int so it's confusing to use them as mixin arguments. Use the [.stringof](https://dlang.org/spec/property.html#stringofhttps://dlang.org/spec/property.html#stringof) property. That should do it.
Re: What is this undefined reference with -betterC about?
On Wednesday, 16 June 2021 at 16:27:13 UTC, Dennis wrote: On Wednesday, 16 June 2021 at 14:38:10 UTC, jfondren wrote: What do I change to 1. a script like this that uses hostname 2. the hostname module so that both can be built with -betterC when and only when the script is using -betterC? That's currently the situation: you can only build when both are betterC or else you get a linker error. It has to be a linker error, dmd cannot know at the time of compiling project A how project B is going to be compiled and vice versa. It's dub that's calling dmd though. Cargo handles this situation with features: https://doc.rust-lang.org/cargo/reference/features.html Where this case would look something like ``` [dependencies] hostname = { version = "0.1.1", features = ["betterC"] } ``` in the script's dub config that uses hostname. I feel like I've seen similar configurations in dub configs, but I see nothing about this in the documentation. It noticed your code looks like this: ```D version(D_BetterC) { char* hostnamez; } else { immutable char* hostnamez; } ``` The different types result in different mangles, causing the linking errors. Why not simply give them the same type? the pragma(crt_constructor) function can't initialize immutables: https://forum.dlang.org/post/wvjfygxfvmoaortmn...@forum.dlang.org
Re: What is this undefined reference with -betterC about?
On Wednesday, 16 June 2021 at 16:27:13 UTC, Dennis wrote: It has to be a linker error, dmd cannot know at the time of compiling project A how project B is going to be compiled and vice versa. Well I suppose you could use a specific dub configuration, maybe giving 'hostname' a targetType "sourceLibrary" or something, but I would just make the abi consistent.
Re: What is this undefined reference with -betterC about?
On Wednesday, 16 June 2021 at 14:38:10 UTC, jfondren wrote: What do I change to 1. a script like this that uses hostname 2. the hostname module so that both can be built with -betterC when and only when the script is using -betterC? That's currently the situation: you can only build when both are betterC or else you get a linker error. It has to be a linker error, dmd cannot know at the time of compiling project A how project B is going to be compiled and vice versa. It noticed your code looks like this: ```D version(D_BetterC) { char* hostnamez; } else { immutable char* hostnamez; } ``` The different types result in different mangles, causing the linking errors. Why not simply give them the same type?
Re: Can not get struct member addresses at compile time
On Wednesday, 16 June 2021 at 11:56:31 UTC, Mike Parker wrote: https://dlang.org/spec/pragma.html#crtctor Very interesting, thanks for the hint! This is definitely a viable solution, though if there's a way to let the linker determine the pointer address, that'd be even better. In C, it's a comparatively standard thing to do: ```c struct Foo{ char bar; }; struct Foo foo; void *ptr = //compiles, links and works ``` Why the D compilers would not pass this down to the linker eludes me.
Re: Can not get struct member addresses at compile time
On Wednesday, 16 June 2021 at 13:36:07 UTC, Ali Çehreli wrote: On 6/16/21 2:27 AM, Doeme wrote: > How does one get the address of a struct member? Here is an experiment with offsetof and opDispatch: Cool stuff! I actually tried a very similar approach once, but it did not work out, since the D compilers refuse to do pointer arithmetic at compile time :/ ```d struct Foo{ ubyte bar; } void* membaddr(void *ptr, ulong offset){ return ptr+offset; } __gshared Foo foo; void* bar = membaddr(, foo.bar.offsetof); //Error: cannot perform arithmetic on `void*` pointers at compile time ``` I guess that the opDispatch-method will suffer from the same issue...
Re: What is this undefined reference with -betterC about?
On Wednesday, 16 June 2021 at 14:21:40 UTC, jfondren wrote: Why isn't this linking? OK, with verbose commands I see that libhostname.a is built without -betterC So that's why this fails to link. What do I change to 1. a script like this that uses hostname 2. the hostname module so that both can be built with -betterC when and only when the script is using -betterC?
Re: Can not get struct member addresses at compile time
On Wednesday, 16 June 2021 at 13:26:43 UTC, jfondren wrote: Is this a bug? Probably. Please file an issue if there isn't one already: https://issues.dlang.org/
What is this undefined reference with -betterC about?
Here's a complete script that you can run right now, using a dub module that I just updated: ```d #!/usr/bin/env dub /+ dub.sdl: dependency "hostname" version="~>0.1.1" buildOptions "betterC" +/ extern(C) void main() { import hostname : hostnamez; import core.stdc.stdio : printf; printf("hostname: %s", hostnamez); } ``` ... which fails: ``` /usr/bin/ld: /tmp/.dub/build/hostnameex2-~master/application-debug-linux.posix-x86_64-dmd_v2.097.0-96F370DD71342805A23ECDFD2C6CCE6C/hostnameex2.o: in function `main': /home/jfondren/mars/learn/./hostnameex2.d:11: undefined reference to `_D8hostname9hostnamezPa' ``` I've rm -rf'd /tmp/.dub and ~/.dub/packages , I've gotten things to a point where I could modify dub's cached hostname/source.d and confirm that e.g. pragma(msg, hostnamez.mangleof) has exactly the same output in that file as in the script above. This all works fine if instead of a dub dependency I add the path to hostname.d in dflags. And this script works fine, without betterC: ```d #!/usr/bin/env dub /+ dub.sdl: dependency "hostname" version="~>0.1.1" +/ void main() { import std.stdio : writeln; import hostname : hostname, hostnamez; import std.string : fromStringz; writeln("hostname: ", hostname); writeln("hostname: ", hostnamez.fromStringz); } ``` Why isn't this linking?
Re: Can not get struct member addresses at compile time
On 6/16/21 2:27 AM, Doeme wrote: > How does one get the address of a struct member? Here is an experiment with offsetof and opDispatch: struct Foo{ ubyte bar; int i; } auto addrOf(T)(ref T t) { static struct AddrOf { void * origin; auto opDispatch(string member)() { return origin + mixin ("T." ~ member ~ ".offsetof"); } } return AddrOf(); } import std.stdio; __gshared Foo foo; void main() { writeln(); writeln(foo.addrOf.bar); writeln(foo.addrOf.i); // Alternative syntax writeln(addrOf(foo).bar); writeln(addrOf(foo).i); } Ali
Re: Can not get struct member addresses at compile time
On Wednesday, 16 June 2021 at 11:56:31 UTC, Mike Parker wrote: https://dlang.org/spec/pragma.html#crtctor "as a simple replacement for shared static this in betterC mode" Cool. However, ```d immutable int example; version(D_BetterC) { pragma(crt_constructor) extern(C) void initialize() { example = 1; } } else { shared static this() { example = 1; } } ``` this compiles without -betterC; with -betterC it errors out: Error: cannot modify `immutable` expression `example` Is this a bug?
Re: Can not get struct member addresses at compile time
On Wednesday, 16 June 2021 at 09:27:25 UTC, Doeme wrote: Is there an alternative to get to this point? Static module initializers are not really an option, since the whole thing should be -betterC. ```D import core.stdc.stdio; struct Foo{ ubyte bar; } __gshared Foo foo; void* baz = void* bar; extern(C): pragma(crt_constructor) void initialize() { bar = } void main() { *(cast(ubyte*)bar) = 10; printf("%d", foo.bar); } ``` https://dlang.org/spec/pragma.html#crtctor
Can not get struct member addresses at compile time
Hi! I'm currently investigating why I can not take the address of a static struct-element at compile time (afaik the linker should be able to resolve this, and doing the identical thing in C works...) ```d struct Foo{ ubyte bar; } __gshared Foo foo; void* baz = \ //works void* bar = \ //Error: static variable `foo` cannot be read at compile time ``` Does this have to do with ".bar" potentially being a function call? How does one get the address of a struct member? The higher level problem of this question is that I want to make a pointer-map of a struct: ```d import std.meta; struct Foo{ ubyte a; ushort b; } template ptrize(alias S){ enum ptrize = \ } __gshared Foo f; static immutable void*[] map = [staticMap!(ptrize, f.tupleof)]; ``` Is there an alternative to get to this point? Static module initializers are not really an option, since the whole thing should be -betterC. Thanks for any hints!
Re: Parallel For
On Wednesday, 16 June 2021 at 06:29:21 UTC, z wrote: On Tuesday, 15 June 2021 at 06:39:24 UTC, seany wrote: ... This is the best I could do: https://run.dlang.io/is/dm8LBP For some reason, LDC refuses to vectorize or even just unroll the nonparallel version, and more than one `parallel` corrupts the results. The same trick as before is useful here: insert a write(i+ii); before the assignment and see if the output looks reasonable. Instead of only unique indices, there are many repeats, as of course (i=0)+(ii=1) == (i=1)+(ii=0) ```d import std; void main() { int[] a = [1, 2, 3, 4, 5, 6, 7, 8, 9]; int[] b = [11, 12, 13, 14, 15, 16, 17, 18]; int[] c = new int[a.length * b.length]; foreach (i, aa; parallel(a)) { foreach (ii, bb; parallel(b)) { c[i * b.length + ii] = aa + bb; } } writeln(c); } ```
Re: What exactly gets returned with extern(C) export string func() ?
On Wednesday, 16 June 2021 at 02:46:36 UTC, cc wrote: I can't seem to get it to work as a return type, but interestingly it does work as an out/pass by ref parameter. Probably for returning the struct it needs some allocation directive in C# but I'm not sure. Maybe C# also tries something to do with the IntPtr. It may work if you use a struct on the DLL side too and convert any specific things like pointers to simple integers instead. The out keyword however basically is just a pointer to the struct, so reading directly from the memory offset from the DLL works instead. As long the GC sees the data alive - .(i)dup doesn't protect your memory here. The data could be collected by the GC anytime the function call goes out of scope.
Re: LNK2019 error in the C++ interface
On Thursday, 10 June 2021 at 15:19:27 UTC, kinke wrote: Confirmed: https://issues.dlang.org/show_bug.cgi?id=22014 Thank you for the bug report. I'm glad I couldn't handle it myself. The only thing that bothers me is that there is no sign of this problem being fixed. I fear that this may be the case forever. On Thursday, 10 June 2021 at 15:19:27 UTC, kinke wrote: Wrt. `tagRECT`, this should come in handy (for a druntime fix): https://dlang.org/changelog/2.097.0.html#pragma-mangle-aggregate I don't see how this helps with the modifications related to tagRECT.
Internal Server Error on reload of dfeed.js
STR: 1. open http://forum.dlang.org/static-bundle/637528586548394375/dlang.org/js/dlang.js+js/dfeed.js 2. press reload (F5 or ctrl+R)
Re: Parallel For
On Tuesday, 15 June 2021 at 06:39:24 UTC, seany wrote: ... This is the best I could do: https://run.dlang.io/is/dm8LBP For some reason, LDC refuses to vectorize or even just unroll the nonparallel version, and more than one `parallel` corrupts the results. But judging by the results you expected and what you described, you could maybe replace it by a ton of `c[] = a[] *operand* b[]` operations? Unless you use conditionals after or do something else that confuses the compiler, it will maybe use SSE/AVX instructions, and at worst use basic loop unrolling.