Issue 1117: Effective type object access requirements

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:

(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.