Authors: Jay Ghiron
Date: 2026-10-01
Submitted against: C23
Status: Open
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- the signed or unsigned type compatible with the underlying type of the effective type of the object,
- the signed or unsigned type compatible with a qualified version of the underlying type of the effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
- a character type.
(C23 6.5.1 "General" paragraph 7.)
This paragraph has two issues. First, consider the following:
#include<wchar.h>
int main(){
const wchar_t s[]=L"1?";
wchar_t*p;
wcstol(s,&p,10);
putwchar(*p);
putwchar(L'\n');
}
This ought to be fine, but none of the bullets seem to allow it.
Specifically, removing qualifiers never appears to be permitted though
it was always the intent to be able to remove const while not
actually modifying the object. Removing volatile is also
specifically forbidden, though that goes even further and forbids
forming the lvalue rather than just accessing the object. Removing
restrict should have no effect. Second, consider the following:
#include<stdio.h>
enum E:int;
int main(){
enum E a=0;
printf("%u\n",*(unsigned*)&a);
unsigned b=0;
printf("%i\n",*(enum E*)&b);
}
The third bullet and fourth bullet are worded weirdly by saying
"compatible with" instead of "corresponding to", though this has been
fixed in C2Y. However, the intent appears to be that a signed integer
type or unsigned integer type can be accessed using the corresponding
integer type of the opposite signedness. In C23 the wording was
changed to specify the underlying type, which means that the first
call to printf is defined since it is the corresponding integer type
of the opposite signedness to the underlying type of E. There is
nothing that allows the reverse though, so the second call to printf
is undefined. I assume that it was not intended for these bullets to
be unidirectional in this case, and that both calls to printf should
have the same validity.
No suggested correction is provided because the proposal N3907 intends on significantly changing this wording. Though if N3931 also gets accepted, that could be used in this paragraph which would be like what C++ does.