digitalmars.D.learn - Why no offsetof for static struct?
- FoxyBrown (23/23) Jul 10 2017 Cannot get the offset of static members of a struct
- Adam D. Ruppe (10/14) Jul 10 2017 That's because static members do not have an offset. They are not
- FoxyBrown (53/67) Jul 10 2017 This is not true, just because there isn't any official
- =?UTF-8?Q?Ali_=c3=87ehreli?= (35/73) Jul 10 2017 Yes but that address is not offset from the beginning of any struct
- Mike Parker (26/51) Jul 10 2017 Every variable has an address. That includes static members of a struct....
- ag0aep6g (50/64) Jul 11 2017 There may be cases where that happens, but it's not guaranteed. Here's
Cannot get the offset of static members of a struct struct X { __gshared public: int x; } X.x.offsetof < invalid. We can clearly get a pointer to the static struct X since &X.x is effectively the address of X(regardless nomenclature and terminology issues in D trying to hide this). e.g., auto p = cast(X*)&X.x; will, for all practical purposes be a pointer to X. auto GetStaticAddress(T)() { mixin("auto p = cast(T*)&T."~__traits(allMembers, T)[0]~";"); return p; } Of course, assuming that the first member is at the same location as the start of the struct and the elements are laid out in the same positions(not sure if this is guaranteed, but probably is). Would be much nicer if we could just take the address of a static struct
Jul 10 2017
On Monday, 10 July 2017 at 20:01:39 UTC, FoxyBrown wrote:Cannot get the offset of static members of a structThat's because static members do not have an offset. They are not part of the struct in memory, just in name.We can clearly get a pointer to the static struct XThere's barely any such thing as a static struct. That's just a struct that stands without outside context.... which is almost all structs, actually, so the term isn't special.since &X.x is effectively the address of X(regardless nomenclature and terminology issues in D trying to hide this).No, it isn't. Static members are stored in an entirely different place than non-static members. They are really just global variables in memory with their in-source name being nested somewhere else.
Jul 10 2017
On Monday, 10 July 2017 at 20:13:46 UTC, Adam D. Ruppe wrote:On Monday, 10 July 2017 at 20:01:39 UTC, FoxyBrown wrote:This is not true, just because there isn't any official statement, or even if denied, does not make it true. I have proof: auto GetStaticAddress(T)() { mixin("auto p = cast(T*)&T."~__traits(allMembers, T)[0]~";"); return p; } Returns the address of a struct's static members. It's pretty obvious, the compiler seems to instantiate the static members simply as a sort of "singleton". They are laid out with the same relative offsets as the struct(which is obvious, as that is the most natural way). That is all that is needed to treat the memory the static variables use as the struct in which they are part of. No need to make it any more complex than that. Just because D obfuscates that static structs have addresses, doesn't mean they don't. No need to perpetuate a misnomer. Static structs and classes have addresses. No, it might not be officially supported and the compiler may end up doing something funky, but it works, and works as it should, and should become part of D because it is useful: auto GetOpts(T)(string[] args) { import std.getopt, std.meta, std.traits; auto t = GetStaticAddress!(T)(); string combine() { string s = ""; foreach(m; AliasSeq!(__traits(allMembers, T))) { mixin("enum a = __traits(getAttributes, T."~m~")[0];"); mixin("s ~= \"`"~a~"`, &"~T.stringof~"."~m~", \";"); } return s; } enum s = combine(); mixin("return getopt(args, "~s~");"); } struct X { align(1): __gshared public static: ("A") bool A; ("B") string B; ("C") string[] C; }; which allows us to do GetOps!X(args) vs getop(args, "A", &X.A, "B", &X.B, "C", &X.C); replaces the overly verbose getopt. Tell me that isn't useful and tell me that static structs don't have addresses!Cannot get the offset of static members of a structThat's because static members do not have an offset. They are not part of the struct in memory, just in name.We can clearly get a pointer to the static struct XThere's barely any such thing as a static struct. That's just a struct that stands without outside context.... which is almost all structs, actually, so the term isn't special.since &X.x is effectively the address of X(regardless nomenclature and terminology issues in D trying to hide this).No, it isn't. Static members are stored in an entirely different place than non-static members. They are really just global variables in memory with their in-source name being nested somewhere else.
Jul 10 2017
On 07/10/2017 02:14 PM, FoxyBrown wrote:On Monday, 10 July 2017 at 20:13:46 UTC, Adam D. Ruppe wrote:Yes but that address is not offset from the beginning of any struct object. What would be its relationship to the following two objects? import std.stdio; auto GetStaticAddress(T)() { mixin("auto p = cast(T*)&T."~__traits(allMembers, T)[0]~";"); return p; } struct S { static int s; int m; } void main() { writeln("S.s is at ", GetStaticAddress!S); auto a = S(); auto b = S(); writeln("a is at ", &a); writeln("b is at ", &b); } Prints S.s is at 7F6D68484710 a is at 7FFEADF41B68 b is at 7FFEADF41B6C So there is no offset of S.s to speak of (i.e. number of bytes from the beginning of) neither from a nor b.On Monday, 10 July 2017 at 20:01:39 UTC, FoxyBrown wrote:This is not true, just because there isn't any official statement, or even if denied, does not make it true. I have proof: auto GetStaticAddress(T)() { mixin("auto p = cast(T*)&T."~__traits(allMembers, T)[0]~";"); return p; } Returns the address of a struct's static members.Cannot get the offset of static members of a structThat's because static members do not have an offset. They are not part of the struct in memory, just in name.We can clearly get a pointer to the static struct XThere's barely any such thing as a static struct. That's just a struct that stands without outside context.... which is almost all structs, actually, so the term isn't special.since &X.x is effectively the address of X(regardless nomenclature and terminology issues in D trying to hide this).No, it isn't. Static members are stored in an entirely different place than non-static members. They are really just global variables in memory with their in-source name being nested somewhere else.It's pretty obvious, the compiler seems to instantiate the static members simply as a sort of "singleton".Makes sense.They are laid out with the same relative offsets as the struct(which is obvious, as that is the most natural way). That is all that is needed to treat the memory the static variables use as the struct in which they are part of. No need to make it any more complex than that.S.s is sitting in memory all by itself without are relation to any other S members.Just because D obfuscates that static structs have addresses, doesn't mean they don't.I assume you mean "static members". Then, yes, of course they have addresses. And you don't even need a function like GetStaticAddress(): writeln("S.s is at ", &S.s);No need to perpetuate a misnomer. Static structs and classes have addresses.Again, I think you mean "static members of" or "instances of" structs and classes. Ali
Jul 10 2017
On 7/11/2017 6:14 AM, FoxyBrown wrote:On Monday, 10 July 2017 at 20:13:46 UTC, Adam D. Ruppe wrote:Every variable has an address. That includes static members of a struct. But their location has absolutely no relationship to any instance of a struct. They have a fixed location in memory. Consider: module Foo; int x; struct Bar { static int y; int z; } There is effectively no difference between x and y here. The only difference is that Bar is part of y's namespace, so you can access them like so: Foo.x; Foo.Bar.y; y's location has no relationship to any instance of Bar, and the declaration of the Bar type has no address. Of course you can take the address of y, as &Bar.y, but you can also take the address of x. Take y out of Bar and the only difference is that you no longer need Bar as part of the namespace. On the other hand: Bar b; writeln(b.z); As an instance of Bar, b *does* have a location in memory. And z *does* have an offset that is relative to that location. So y.offsetof does not exist, because there is no instance of Bar to which it can have a relative address.No, it isn't. Static members are stored in an entirely different place than non-static members. They are really just global variables in memory with their in-source name being nested somewhere else.This is not true, just because there isn't any official statement, or even if denied, does not make it true. I have proof: auto GetStaticAddress(T)() { mixin("auto p = cast(T*)&T."~__traits(allMembers, T)[0]~";"); return p; } Returns the address of a struct's static members. It's pretty obvious, the compiler seems to instantiate the static members simply as a sort of "singleton". They are laid out with the same relative offsets as the struct(which is obvious, as that is the most natural way). That is all that is needed to treat the memory the static variables use as the struct in which they are part of. No need to make it any more complex than that.
Jul 10 2017
On 07/10/2017 11:14 PM, FoxyBrown wrote:auto GetStaticAddress(T)() { mixin("auto p = cast(T*)&T."~__traits(allMembers, T)[0]~";"); return p; } Returns the address of a struct's static members.No, it returns the address of T's first member.It's pretty obvious, the compiler seems to instantiate the static members simply as a sort of "singleton". They are laid out with the same relative offsets as the struct(which is obvious, as that is the most natural way). That is all that is needed to treat the memory the static variables use as the struct in which they are part of. No need to make it any more complex than that.There may be cases where that happens, but it's not guaranteed. Here's an example where static members don't get stored together: ---- struct SA { static int x; static immutable int y; } struct SB { static int x; static immutable int y; } struct D { int x; immutable int y; } const(void)*[] addressesOfMembers(alias thing)() { import std.meta: AliasSeq; static if (is(thing)) alias T = thing; else alias T = typeof(thing); const(void)*[] addresses; foreach (m; AliasSeq!(__traits(allMembers, T))) { addresses ~= &__traits(getMember, thing, m); } return addresses; } void main() { import std.stdio; writeln("members of SA: ", addressesOfMembers!SA); writeln("members of SB: ", addressesOfMembers!SB); D d; writeln("members of d: ", addressesOfMembers!d); } ---- Prints something like this (Ubuntu, x86-64): ---- members of SA: [7F7B2A294E90, 55EB7957FE94] members of SB: [7F7B2A294E94, 55EB7957FE9C] members of d: [7FFDD1F2E4B8, 7FFDD1F2E4BC] ---- Note that SA's second member is stored far away from its first member. Same for SB. Also, SB's second member is stored between SA's members. In contrast, d's members are packed together, because they're not static.
Jul 11 2017