www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why no offsetof for static struct?

reply FoxyBrown <Foxy Brown.IPT> writes:
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
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 10 July 2017 at 20:01:39 UTC, FoxyBrown wrote:
 Cannot get the offset of static members of a struct
That'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 X
There'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
parent reply FoxyBrown <Foxy Brown.IPT> writes:
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:
 Cannot get the offset of static members of a struct
That'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 X
There'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.
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!
Jul 10
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 07/10/2017 02:14 PM, FoxyBrown wrote:
 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:
 Cannot get the offset of static members of a struct
That'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 X
There'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.
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.
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.
 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
prev sibling next sibling parent Mike Parker <aldacron gmail.com> writes:
On 7/11/2017 6:14 AM, FoxyBrown wrote:
 On Monday, 10 July 2017 at 20:13:46 UTC, Adam D. Ruppe wrote:
 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.
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.
Jul 10
prev sibling parent ag0aep6g <anonymous example.com> writes:
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