Description
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 commentedon Jul 10, 2022
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 commentedon Jul 10, 2022
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)
is4
, 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?It is even that the result of the same expression
sizeof(S)
in different translation units can be different numbers because they are 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
Then explicitly says
This would make the meaning clear.
jensmaurer commentedon Jul 10, 2022
Yes, an implementation can choose to make
sizeof(S)
== 4. Or 13.I don't see a defect here.
xmh0511 commentedon Jul 11, 2022
The defect is, that the intended meaning is ambiguous between unspecified behavior and undefined behavior. [intro.defs.defns.undefined] says
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 commentedon Jul 11, 2022
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 commentedon Jul 11, 2022
Uh... Assume there is only one definition for
S
in TU, ODR is powerless here. So, I would say the results ofsizeof(S)
do not vary from the different definitions ofS
. 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 commentedon Jul 11, 2022
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 commentedon Jul 11, 2022
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:
be clear.
jensmaurer commentedon Jul 11, 2022
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 commentedon Jul 11, 2022
IIUC, please see #91 (comment).
[-][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?[/+]jensmaurer commentedon Jul 15, 2022
CWG2609
xmh0511 commentedon Jun 16, 2023
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?