Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sizeof() of an struct is not treated like a constant like sizeof(int). #15116

Closed
redknightlois opened this issue Nov 9, 2016 · 7 comments
Closed

Comments

@redknightlois
Copy link

redknightlois commented Nov 9, 2016

Version Used: C# 6.0

Steps to Reproduce:

internal unsafe struct FixedPageLocator
{
    [StructLayout(LayoutKind.Explicit, Size = 4)]
    private struct PageData
    {                
    }

    private fixed byte Tables[CedarRootHeader.TotalNumberOfPages * sizeof(PageData)];
}

Expected Behavior: At compile time sizeof(PageData) is a constant, for all states and purposes the sizeof statement of should compile when you are working with an struct in the same way if you are using sizeof(int).

Actual Behavior: Fails with
CS0133 The expression being assigned to 'CedarPage.FixedPageLocator.Tables' must be constant

EDIT: After a second though, by-product of this change would be the ability of allowing fixed buffers for blittable types too. So this can be enabled too:

private fixed PageData Tables[CedarRootHeader.TotalNumberOfPages];
@svick
Copy link
Contributor

svick commented Nov 9, 2016

This seems to be according to the spec:

The result of the sizeof operator is a value of type int. For certain predefined types, the sizeof operator yields a constant value as shown in the table below.

For all other types, the result of the sizeof operator is implementation-defined and is classified as a value, not a constant.

Do you think the spec should be changed?

@tannergooding
Copy link
Member

tannergooding commented Nov 9, 2016

In this case, PageData should actually have a size of 4, but that is not always the case.

For example, if you were to declare:

[StructLayout(LayoutKind.Explicit, Size = 4)]
private struct PageData
{
    [FieldOffset(0)]
    private long _unused;
}

Then sizeof(PageData) will return 8, not 4.

It can get even more complicated in other scenarios where the layout may actually depend on runtime layout (such as if you used IntPtr, whose size depends on the architecture).

@gafter
Copy link
Member

gafter commented Nov 9, 2016

See also #3208

@qrli
Copy link

qrli commented Nov 10, 2016

@redknightlois It is because the size of struct is indeed non-constant. It may change according to CPU architecture and memory alignment.

Size of explicitly sized/layout/aligned structs does be constant though. However, in current C#, there is no notation of explicitly sized/layout/aligned (unmanaged) struct. This is also a common issue when using generic sizeof(T), even when T is int.

@redknightlois
Copy link
Author

redknightlois commented Nov 10, 2016

@tannergooding That case it is a semantic bug. If you do that, you are in deep troubles way before the compiler/runtime would arbitrarily choose one or another. That should even generate a warning at the compiler level as it is pretty easy to detect. A static typed language should be expected to limit/notice those kind of errors and probably deserves an issue on its own.

@svick if you put it that way, yes. Mainly, because, sizeof() is already being treated differently for different cases. The main issue at the spec level is that it is being overly conservative for no reason. I do agree that on some architectures you cannot expect to know how big a pointer/reference is, but if the struct is composed of safe\blittable components, there is no reason why it should be disallowed.

@gafter agree, this is a subcase on that and yet another C# for performance high in my wish list :). Having blittable constrains solve this completely; even though this can be solved independently of blittable as it is a more restricted case and there is no need to introduce anything into the language itself. cc @qrli

Currently this is the kind of unsafe (in the sense of brittle) code I have to write.

internal unsafe struct FixedPageLocator
{
    [StructLayout(LayoutKind.Explicit, Size = 4)]
    private struct PageData
    {                
    }

    private fixed byte Tables[CedarRootHeader.TotalNumberOfPages * 4];
}

@Unknown6656
Copy link

If we take request/issue #15079 and its referenced sub-issues into consideration for upcoming C# versions, this should no longer be a problem 😉

@CyrusNajmabadi
Copy link
Member

Closing this out. We're doing all language design now at dotnet/csharplang. If you're still interested in this idea let us know and we can migrate this over to a discussion in that repo. Thanks!

@CyrusNajmabadi CyrusNajmabadi closed this as not planned Won't fix, can't repro, duplicate, stale Nov 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants