Re: Structs

Tech-Archive recommends: Fix windows errors by optimizing your registry

From: Daniel O'Connell [C# MVP] (onyxkirx_at_--NOSPAM--comcast.net)
Date: 05/03/04


Date: Mon, 3 May 2004 16:21:53 -0500


"cody" <no_spam_deutronium@gmx.net> wrote in message
news:uzGwZXOMEHA.3668@TK2MSFTNGP11.phx.gbl...
>> A struct is created, generally, in null memory. I'm pretty sure the .NET
>> memory model ensures that a variable created on the stack retains a zero
>> value, even if its unassigned. I could be wrong but it would seem
> unlikely.
>
> No. Locals and structs are created on the stack which does *not* contain
> zeros, but instead data of previous method invocations.
> If a method returns it would have to overwrite the stack with zeros to
> clean
> up, if you want the behavour that every struct is generated in "null
> memory".
That is partially incorrect, as was my original statement.

[quote from CIL Partition 1, page 87 of the MSWord version]
A local variable may hold any data type. However, a particular slot shall
be used in a type consistent way (where the type system is the one described
in clause 11.3.2.1). Local variables are initialized to 0 before entry if
the initialize flag for the method is set (see Section 11.2). The address
of an individual local variable may be taken using the ldloca instruction.
[end quote]

Note "Local variables are initialized to 0 before entry if the initalize
flag for the method is set". This shows that variables are initalized to 0
in almost every case(I've *NEVER* seen IL without that flag), and in this
case the C# compiler generates superflous code with the initobj instruction.
So, indeed, there is generally no reason to do this(and, actually, reference
variables will always be null at calltime, both in and outside of valuetypes
on the stack). Other tests have shown that booleans are set to false as
well(I've yet to manage to make it have a different value). I do wonder
about performance here...it seems to me that it would be as or perhaps more
efficient to zero the small local block(which is almost always small) than
it would be to analyze the local block and zero out only select fields. That
does seem odd to me.

Also, this same document virtualizes the stack as a singly linked list,
meaning that there is no apparent explicit requirement for saving stack
frames in any given place or for using a traditional growing stack. While I
do think the current implementation does use that for ease of implementation
reasons, it isn't definite and assuming that a new stack frame would exist
where an old one did will probably be incorrect at some point.
>
> C# forces you to initialize *every* local variable completely before first
> use. In the case of structs a ctor call is not needed if you assign all
> fields manually.
>

Yes, but I don't think it has much to do with the underlying system as much
as clean coding. Forcing explicit definition forces you to know what is
assigned(and makes life easier since you don't have to worry about the
differing defaults that can come up). The CLR doesn't require it, its
strictly a convention forced by C#(which also sets the init flag, causing
double zeroing). Also, while this looks like a constructor call, it isn't,
its C# sugar(at least in most cases, I havn't tested valuetypes with default
constructors. C++ should allow this, but it may or may not be consumable by
C#). For a value type, a call instruction is issued to call the constructor,
vs a newobj instruction which is used for a reference type. The entire
purpose of initobj is to initalize to zero\null\0.0\false(although for
pimatives like bool, the C# compiler emits ldc.i4.0 instead of initobj).

>
> Think: Would the initobj call would make sense in any circumstance when
> structs would already zeroed out a creation time?

No, but its there, one would hope the JIT would ignore it. This is an
artifiact of the compiler. I would assume the C# compiler flow control
doesn't interlink with the codegen, the compiler doesn't explicitly need to
emit initobj because it sets the local init flag, however instead of
attempting an optimization of tracking variable usage and deciding when to
issue the initobj instruction, the compiler prefers to do a literal(and
simplier) translation of your code and emits the initobj instruction.
However, due to some strange inconsistencies in the runtime, there is a
chance that initobj is needed in the case you are using strange valuetypes.

>
>> As a matter of technical fact, I don't believe that its required to init
>> a
>> struct before use. C# tends to disallow it, however, under assignment
>> rules(I've run into one situation where it seems to be allowed, which I
> have
>> to check on). I think that is more for the purposes of correct, well
> though
>> out code more so than it is a problem with the underlying platform.
>
> Which situation? I'd like to hear.

There isn't one, per se. It is either 1) a bug in this complier or 2) the
convention is being dropped. Sometime in the near future I'll make an
inquiry about that, but its irrelevent right now.

Now, if you have proof(empirical, anecdotal, or documented) of an error
here, I am quite interested. The docs aren't particularly clear and my
reading may or may not be correct. I am not interested in C++ or x86's
memory or call models however.
>
> --
> cody
>
> Freeware Tools, Games and Humour
> http://www.deutronium.de.vu || http://www.deutronium.tk
>
>



Relevant Pages

  • Re: Value Types and Reference Types
    ... struct can be thought of as a lightweight version of a class. ... but C# itself doesn't mention the stack vs heap at all. ... able to say that local variables are always on the stack. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: How to "define" a struct
    ... I WANT the struct on the stack ... All types have a default constructor. ... local variables don't automatically use the default constructor. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Pointer to the out of scope local variables
    ... but somtimes we need to return local variables address to the caller.Is it valid to do so? ... When function returns the stack area taken by the function is reclaimed back. ... All local variables cease to exists at this point. ... struct X {... ...
    (microsoft.public.vc.language)
  • Re: A solution for the allocation failures problem
    ... struct nested *ptr1; ... which would jump to label if the allocation failed. ... implemented for the stack under windows. ... So in the malloc instance I would say you make use of the pre-allocated reserve rather than freeing it so you can do further mallocs whilst recovering. ...
    (comp.lang.c)
  • Re: Local variables controversial?
    ... >>>Calforth uses local variables, but doesn't set a policy of what's good ... they are implemented using a stack frame. ... is still on the Forth data stack? ...
    (comp.lang.forth)