10

Does taking address of a C# struct cause default constructor call?

For example, I got such structs:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct HEADER {
    public byte OPCODE;
    public byte LENGTH;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct S {
    public HEADER Header;
    public int Value;
}

Then, of course, I can't do this:

S s;                // no constructor call, so...
var v = s.Value;    // compiler error: use of possibly unassigned field 'Value'

But once I obtain pointer to the struct, I can read its fields even without using the pointer, and even embedded struct's fields:

S s;
S* ps = &s;
var v1 = ps->Value;        // OK, expected
var v2 = s.Value;          // OK!
var len = s.Header.LENGTH; // OK!

So, does it call the default constructor somehow, or - once I take the address - C# stops caring about the memory?

PS: The memory seems to be zero-initialized anyway.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
lisz
  • 435
  • 5
  • 9
  • 1
    I think its just a case of all-bets-are-off, and it washes its hands at what you are trying to do in an unsafe environment, – TheGeneral Feb 08 '19 at 09:33
  • 2
    You don't need a pointer for that. `var s = default(S);` – Kevin Gosse Feb 08 '19 at 09:34
  • if it enforced that rule with pointers, you could imagine the case where go away and do all sorts of wierd and wonderful things to the struct using its pointer, how is it going to know, and you wouldn't be able to compile. – TheGeneral Feb 08 '19 at 09:41
  • 2
    If you're using pointers, you're already using `unsafe` - at that point you already have **zero** protections against... anything. – Marc Gravell Feb 08 '19 at 10:13

1 Answers1

10

Does taking address of a C# struct cause default constructor call?

No. It just circumvents the compiler check.

The "use of possibly unassigned field" is a nicety to protect you against yourself. But it can easily be worked around. And in this case it does not seem so critical.

PS: The memory seems to be zero-initialized anyway.

Yes, that will almost always (see below) be the case in .NET, making the "default constructor call" question a bit academic. What happens to your memory is not so tightly coupled to the compiler warning.

H H
  • 263,252
  • 30
  • 330
  • 514
  • 3
    re your last line: that's not actually true - you can suppress the locals init flag via IL hack, and IIRC they were planning to make it possible via attribute too - it has shown valuable in some cases; the most visible place this manifests visible differences is in `stackalloc` (the stack-space isn't zero'd, like it usually is), but anything that bypasses definite assignment (like here) would also do the same. It is true to say that *by default* the C# compiler always wipes the space, but that's not the same thing as saying that it is always the case in .NET (or even always the case in C#) – Marc Gravell Feb 08 '19 at 10:12
  • Marc, you're right, this is a little overstated. And I wasn't aware of the attribute developments. I'll add a word. – H H Feb 08 '19 at 10:40
  • 3
    FYI: `System.Runtime.CompilerServices.SkipLocalsInitAttribute`; you might need to declare it yourself, though - see: https://github.com/dotnet/corefx/issues/29026 – Marc Gravell Feb 08 '19 at 10:41