www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - static array of structs clarification questions

reply WhatMeWorry <kheaser gmail.com> writes:
I was thinking about fixed length arrays of structures the other 
day so I played around with the flowing code:

    struct Foo
     {
         int    i;
         string str;
         void info() { writeln("i = ", i, "str = ", str); }
     }

     Foo[2] foos;

     auto f1 = Foo(1, "6chars");  // this string is 6 chars long
     auto f2 = Foo(2, "ThisVeryVeryVeryLongStringHas36Chars");

     foos[0] = f1;
     foos[1] = f2;

     writeln("f1 = ", foos[0]);
     writeln("f2 = ", foos[1]);

     writeln("array foos size in bytes is ", foos.arrayByteSize);
     writeln("array foos has ", foos.length, " elements");
     writeln("foos array consists of ", foos);

The output was
f1 = Foo(1, "6chars", null)
f2 = Foo(2, "ThisVeryVeryVeryLongStringHas36Chars", null)
array foos size in bytes is 32
array foos has 2 elements
foos array consists of [Foo(1, "6chars", null), Foo(2, 
"ThisVeryVeryVeryLongStri
ngHas36Chars", null)]


question #1: The static array must contain the fat pointers to 
str variables. But where is the string data itself actually held: 
the stack? the heap? somewhere else? (does it vary depending on 
location or scope)

question #2: If the above struct was to contain the same struct 
and the second one contains a third, how would the lower structs 
be allocated?  Is it "turtles all the way down?

question #2: Of what use is the nulls in the array elements?  
When I took out the member function: void info(), the nulls went 
away.

Thanks.
Feb 12 2016
next sibling parent anonymous <anonymous example.com> writes:
On 12.02.2016 22:08, WhatMeWorry wrote:
 question #1: The static array must contain the fat pointers to str
 variables. But where is the string data itself actually held: the stack?
 the heap? somewhere else? (does it vary depending on location or scope)
Depends on how the string was created. You can create dynamic arrays over any memory. (Remember: string is an alias of immutable(char)[], i.e. a dynamic array.) I'm not sure where strings from literals are located. Could be some static data section in the executable, or some such. That's beyond me.
 question #2: If the above struct was to contain the same struct and the
 second one contains a third, how would the lower structs be allocated?
 Is it "turtles all the way down?
Struct data is put right where the variable is. Unlike classes and arrays, structs are not references to some other location. When a struct has a struct member, then the data of the member is put right next to the parent's data. The size of the member is added to the parent's size. One consequence of this is that you can't have trees with just structs: `struct Node {Node left; Node right;}` - not gonna fly.
 question #2: Of what use is the nulls in the array elements? When I took
 out the member function: void info(), the nulls went away.
My guess is that you declared the struct in a function (e.g. main), and the null is the context pointer. Put the struct declaration at module scope, or make it `static`, and the null thing should go away. A context pointer is needed when the struct references data from the surrounding function scope. You don't do that here, but the compiler is apparently not smart enough to figure that out.
Feb 12 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/12/16 4:08 PM, WhatMeWorry wrote:
 I was thinking about fixed length arrays of structures the other day so
 I played around with the flowing code:

     struct Foo
      {
          int    i;
          string str;
          void info() { writeln("i = ", i, "str = ", str); }
      }

      Foo[2] foos;

      auto f1 = Foo(1, "6chars");  // this string is 6 chars long
      auto f2 = Foo(2, "ThisVeryVeryVeryLongStringHas36Chars");

      foos[0] = f1;
      foos[1] = f2;

      writeln("f1 = ", foos[0]);
      writeln("f2 = ", foos[1]);

      writeln("array foos size in bytes is ", foos.arrayByteSize);
      writeln("array foos has ", foos.length, " elements");
      writeln("foos array consists of ", foos);

 The output was
 f1 = Foo(1, "6chars", null)
 f2 = Foo(2, "ThisVeryVeryVeryLongStringHas36Chars", null)
 array foos size in bytes is 32
 array foos has 2 elements
 foos array consists of [Foo(1, "6chars", null), Foo(2,
 "ThisVeryVeryVeryLongStri
 ngHas36Chars", null)]


 question #1: The static array must contain the fat pointers to str
 variables. But where is the string data itself actually held: the stack?
 the heap? somewhere else? (does it vary depending on location or scope)
It's stored in the static data segment. Basically, directly in the executable.
 question #2: If the above struct was to contain the same struct and the
 second one contains a third, how would the lower structs be allocated?
 Is it "turtles all the way down?
The only way to compose a struct with itself is to use pointers. You can't place a Foo inside a Foo, because it would be infinite in size (the compiler will complain)
 question #2: Of what use is the nulls in the array elements? When I took
 out the member function: void info(), the nulls went away.
That's odd. I think anonymous probably has the answer (they are context pointers), but I'm also surprised they are null, they shouldn't be. -Steve
Feb 12 2016
parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Friday, 12 February 2016 at 21:56:09 UTC, Steven Schveighoffer 
wrote:
 That's odd. I think anonymous probably has the answer (they are 
 context pointers), but I'm also surprised they are null, they 
 shouldn't be.
In this example, `void foo()` doesn't access any outer variables, so there's no need for a context to be created.
Feb 13 2016
parent reply ZombineDev <valid_email he.re> writes:
On Saturday, 13 February 2016 at 10:22:36 UTC, Marc Schütz wrote:
 On Friday, 12 February 2016 at 21:56:09 UTC, Steven 
 Schveighoffer wrote:
 That's odd. I think anonymous probably has the answer (they 
 are context pointers), but I'm also surprised they are null, 
 they shouldn't be.
In this example, `void foo()` doesn't access any outer variables, so there's no need for a context to be created.
Yes, but the compiler will create a context regardless of this. See also this issue: https://issues.dlang.org/show_bug.cgi?id=15343
Feb 13 2016
parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Saturday, 13 February 2016 at 14:53:39 UTC, ZombineDev wrote:
 On Saturday, 13 February 2016 at 10:22:36 UTC, Marc Schütz 
 wrote:
 On Friday, 12 February 2016 at 21:56:09 UTC, Steven 
 Schveighoffer wrote:
 That's odd. I think anonymous probably has the answer (they 
 are context pointers), but I'm also surprised they are null, 
 they shouldn't be.
In this example, `void foo()` doesn't access any outer variables, so there's no need for a context to be created.
Yes, but the compiler will create a context regardless of this. See also this issue: https://issues.dlang.org/show_bug.cgi?id=15343
It adds a hidden member, but it doesn't actually allocate a context, therefore the member is null: auto foo() nogc { int j; struct Foo { int i; void info() { i += 5; } } return Foo(); } Replace `i` by `j`, and it no longer compiles, because then it really allocates a context. As for your bug report: I believe the documentation specifies the current behaviour somewhere, but I cannot find it now. Nested structs always have a context pointer, except if they don't have methods (for layout compatibility with C). I think this is necessary to avoid "paradoxa" like the following: int j; struct Foo { int i; void info() { static if(Foo.sizeof == 4) j += 5; else i += 5; } }
Feb 13 2016