www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why large binary sizes with struct declaration? - why.d

reply Braden MacDonald <bradenm_k shaw.ca> writes:
Hi everyone, 
 I'm wondering, why does code like this:
____why.d_____________________________________ 
 
struct exampleObj {
uint[1024*32] mydata; 
} 
 
int main() { 
	return 0; 
} 
 
____end of
file_______________________________ 
 
produce an object file that is 129.6 KB??
As far as I understand, the exampleObj should only be a compile-time
definition, and not an object built into the binary because I never declare an
instance of it. (If I comment out the struct exampleObj declaration, the .o
file goes down to 1.5KB. ) 
 
My question is, why does this make a difference? 
May 13 2004
parent reply Kevin Bealer <Kevin_member pathlink.com> writes:
Remember how D allows you to specify initial values for fields in structs?
Apparently this is done by using a memcpy from an example object, in new.  This
should be more compact and probably faster than the alternative - a procedural
constructor definition.  Except in your case, where the object could be built
with a loop instead of thousands of assignments.

(I am interpreting gdc assembler output.  I've found it interesting to compare
assembler: compile twice with a small change and use a graphical diff util.)

The object you define is not "static" so the definition could be used by another
module.  However, I tried making it "static struct {" and that did not have an
effect.

Kevin

In article <c81h4p$1uk6$1 digitaldaemon.com>, Braden MacDonald says...
Hi everyone, 
 I'm wondering, why does code like this:
____why.d_____________________________________ 
 
struct exampleObj {
uint[1024*32] mydata; 
} 
 
int main() { 
	return 0; 
} 
 
____end of
file_______________________________ 
 
produce an object file that is 129.6 KB??
As far as I understand, the exampleObj should only be a compile-time
definition, and not an object built into the binary because I never declare an
instance of it. (If I comment out the struct exampleObj declaration, the .o
file goes down to 1.5KB. ) 
 
My question is, why does this make a difference? 


begin 0644 why.d
M+RH =VAY+F0*("` ,C(Q+C  2T( 8V]M<&EL960 )B!L:6YK960*("` ,3(Y
M+C8 2T( 8V]M<&EL960 *"YO(&9I;&4 ;VYL>2D*"B` ("YO8FH 9FEL92!I
M<R`G;VYL>2< ,2XU2T( :68 =&AE('-T<G5C="!D969I;FET:6]N(&ES(&-O
M;6UE;G1E9"!O=70N"BHO" H*<W1R=6-T(&5X86UP;&5/8FH >PH)=6EN=%LQ
M,#(T*C,R72!M>61A=&$["GT*+R\ 22!D;VXG="!D96-L87)E(&%N>2!I;G-T
M86YC97, ;V8 86X 97AA;7!L94]B:B!O8FIE8W0N" II;G0 ;6%I;B I('L*
-"7)E='5R;B`P.PI]"GAA
`
end

May 13 2004
parent reply Braden MacDonald <bradenm_k shaw.ca> writes:
Yes, but in my mind, it is only a definition at compile time. The only time I
want to use this definition would be from another file, via "import why". 
___ How I think of it ______

int;

int main() {
return 0;
}
____________________________

In that code, all I'm saying is that there is such a thing as int, merely for
compiler verification of any code referencing it. I am not declaring an int,
because I never give it a name. Same thing with the struct. So why does it get
into the binary?



The way I use it is something like this:

____helper.d________________
struct Elephant {
uint[1024*32] toes;

int count() {
int count;
for (int i=0;i<toes.length;i++) {
if (toes[i] != 0) {
count++;
}
}
return count;
}
}

______main.d________________
import helper;

int main {
Elephant e1;
ei.toes[7] = 1454325;
printf("The elephant has %d big toes.", e1.count());
return 0;
}
____________________________

So why does the helper.d object file contain binary space for the Elephant
object? 


Sorry if code is wrong or explanation hard to understand; it's morning here and
I'm in a hurry. Thanks.
May 14 2004
parent reply Kevin Bealer <Kevin_member pathlink.com> writes:
In article <c82mba$i2i$1 digitaldaemon.com>, Braden MacDonald says...
Yes, but in my mind, it is only a definition at compile time. The only time I
want to use this definition would be from another file, via "import why". 

I think what you are seeing is not an object of this type, but rather static data that is essentially part of the constructor definition and thus created in the module where you define the class. For an object that is 128 bytes and has a lot of entropy in the initialization values, this technique is probably very beneficial. Imagine the (generated) constructor definition to look like this: /+ Note: this is a guess by me, haven't looked at the compiler code. +/ why::exampleObj::this { byte * boilerplate = "\0\0\0\0\0....\0"; // 128 KB memcpy(this, boilerplate, 128*1024*1024); /+ your constructor would be inlined here +/ } The same thing happens in the following code: --- int foo(double x) { return x += strlen("alphabet soup"); } int main(char[][] argv) { return argv.size(); } --- The string literal is never used, and the function is never called; but the binary will probably still contain both. Because foo() is emitted, the string literal has to be. Global analysis could possibly remove these unused parts. It would have to be done at link time, right? Otherwise another module might call the constructor. Kevin
May 14 2004
parent Braden MacDonald <bradenm_k shaw.ca> writes:
Ah, I see now. That helps a lot - thanks. 
 
In article
<c82odg$l0i$1 digitaldaemon.com>, Kevin Bealer says... 
I think what you are

data that is

in
the module

has
a lot of

very
beneficial. 
 
Imagine the (generated) constructor definition to look like this: 
 
/+ Note: this is a guess by me, haven't looked at the compiler code. +/ 
 
why::exampleObj::this 
{ 
byte * boilerplate = "\0\0\0\0\0....\0"; // 128 KB 
memcpy(this, boilerplate, 128*1024*1024); 
 
/+ your constructor would be inlined here +/ 
} 

May 15 2004