Skip to content

CWG2609 [expr.sizeof] The result of applying sizeof to empty class is standard? #89

Closed
cplusplus/draft
#5560
@xmh0511

Description

@xmh0511

Full name of submitter (unless configured in github; will be published with the issue): Jim X

[expr.sizeof] p1 says

The result of sizeof applied to any of the narrow character types is 1. The result of sizeof applied to any other fundamental type ([basic.fundamental]) is implementation-defined.

This rule means the result of sizeof to a non-narrow-character fundamental type is implementation-defined. The standard says nothing about whether the result of sizeof to a class type is implementation-defined or not, it just says

When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array.

It can only infer that sizeof to a class type that contains a subobject of a non-narrow-character fundamental type is also implementation-defined, as per [expr.sizeof] p1. This raises a issue, consider that

struct S{};
sizeof(S); // all implementations say the result is 1

[intro.object] p8 only says

Unless it is a bit-field, an object with nonzero size shall occupy one or more bytes of storage, including every byte that is occupied in full or in part by any of its subobjects.

It didn't specify a concrete number, merely the number is at least one. Such a class type does not contain any subobjects of fundamental types, as aforementioned, the result of sizeof to such a type is not clear whether it is guaranteed by standard or specified with implementation-defined.

All consistent behavior of implementations as if to say the result should be guaranteed by the standard but it was omitted in the standard.

Suggested resolution

we may need to clearly say that the result of sizeof applied to any type is implementation-defined except for narrow character types.

Activity

jensmaurer

jensmaurer commented on Jul 10, 2022

@jensmaurer
Member

Since distinct complete objects need to have distinct addresses, the sizeof of any type must not be zero. Since we also don't say anything normative about padding (other than that it might exist), "sizeof" of a class type is essentially unspecified. (The difference vs. implementation-defined is that the implementation needs to document its choices for the latter case. The current wording doesn't impose that for class types, which seems reasonable. If you desire otherwise, write a paper.)

I'm not seeing a defect here.

xmh0511

xmh0511 commented on Jul 10, 2022

@xmh0511
Author

Since distinct complete objects need to have distinct addresses, the sizeof of any type must not be zero.

This part is specified in [intro.object] p8 I have cited it here. The concern is that, if implementation said the result of sizeof(S) is 4, would the implementation conform to the standard? Even more, if it is said to be unspecified, then whether [basic.life] p8 can work if a user-defined library is shared and used by two implementations since the following is always unspecified?

the storage that O2 occupies exactly overlays the storage that O1 occupied

It is even that the result of the same expression sizeof(S) in different translation units can be different numbers because they are unspecified.


Since we also don't say anything normative about padding (other than that it might exist), "sizeof" of a class type is essentially unspecified.

This depends on whether an object of the class type in an array contains the padding bits. Maybe, in [basic.types.general] p4, we should say

Bits in the object representation that are not part of the value representation are padding bits, which are unspecified.

Then explicitly says

When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array, which is unspecified.

This would make the meaning clear.

jensmaurer

jensmaurer commented on Jul 10, 2022

@jensmaurer
Member

Yes, an implementation can choose to makesizeof(S) == 4. Or 13.

I don't see a defect here.

xmh0511

xmh0511 commented on Jul 11, 2022

@xmh0511
Author

Yes, an implementation can choose to makesizeof(S) == 4. Or 13.

I don't see a defect here.

The defect is, that the intended meaning is ambiguous between unspecified behavior and undefined behavior. [intro.defs.defns.undefined] says

behavior for which this document imposes no requirements

[Note 1: Undefined behavior may be expected when this document omits any explicit definition of behavior or ... — end note]

How many padding bits are not explicitly defined when an object of a class type is placed in an array. From this perspective, is the result of sizeof(S) considered UB? Obviously, that's not the intent. The improvement would be to explicitly specify what kind of the behavior is(i.e. unspecified).


Incidentally, Is it even that the results of the same expression sizeof(S) in the same program can be different for different evaluations? This also conforms to the definition of unspecified behavior because this is specified by [intro.abstract] p3.

jensmaurer

jensmaurer commented on Jul 11, 2022

@jensmaurer
Member

There are still requirements about types (e.g. the ODR) and linkage which essentially mean that sizeof(S) must be constant throughout the program.

xmh0511

xmh0511 commented on Jul 11, 2022

@xmh0511
Author

There are still requirements about types (e.g. the ODR) and linkage which essentially mean that sizeof(S) must be constant throughout the program.

Uh... Assume there is only one definition for S in TU, ODR is powerless here. So, I would say the results of sizeof(S) do not vary from the different definitions of S. As well, the program only contains one TU, [basic.link] also is not helpful here. Even if they can apply here, they do not have any requirements on what the number of bytes an object of a type occupies. This may touch on a deeper issue. Anyway, the subject of this issue is to explicitly specify the behavior with unspecified behavior if we intend to say since it is hard to distinguish between unspecified and undefined behavior if the unspecified behavior is not explicitly specified.

jensmaurer

jensmaurer commented on Jul 11, 2022

@jensmaurer
Member

I think what we have here is neither. It's not implementation-defined (no documentation requirement) and it's not unspecified (we shouldn't pretend it might vary from evaluation to evaluation). It's "implementation-defined without documentation requirement", it seems.

xmh0511

xmh0511 commented on Jul 11, 2022

@xmh0511
Author

It's "implementation-defined without documentation requirement", it seems.

It's a good idea to limit the possible executions for the construct by using "implementation-defined without documentation requirement". However, we should first make the concept:

how many possible executions in a program for a construct(i.e. sizeof(int)) that is defined as implementation-defined behavior?

be clear.

jensmaurer

jensmaurer commented on Jul 11, 2022

@jensmaurer
Member

sizeof(int) is implementation-defined, thus a parameter of the abstract machine per [intro.abstract], thus it can't vary within a single run of the abstract machine.

Where's the defect in that area?

xmh0511

xmh0511 commented on Jul 11, 2022

@xmh0511
Author

IIUC, please see #91 (comment).

changed the title [-][expr.sizeof] The result of applying sizeof to empty class is standard?[/-] [+]CWG2609 [expr.sizeof] The result of applying sizeof to empty class is standard?[/+] on Jul 15, 2022
jensmaurer

jensmaurer commented on Jul 15, 2022

@jensmaurer
Member
xmh0511

xmh0511 commented on Jun 16, 2023

@xmh0511
Author

The amount and placement of padding in a class type is unspecified

The unspecified behavior can have multiple possible executions per [intro.abstract] p3, does it mean the result of sizeof(Class) can be different between evaluation to evaluation in a single run of the program?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @xmh0511@jensmaurer

      Issue actions

        CWG2609 [expr.sizeof] The result of applying sizeof to empty class is standard? · Issue #89 · cplusplus/CWG