A
ais523
(This post is about C11.)
I'm trying to maintain some existing code; in particular, there are some
struct fields that I suspect are being written directly rather than via
functions designed for the purpose. I'm trying to handle this with the
following idiom:
struct some_struct {
union {
const int field;
int field_writable;
};
}
Here, the struct used to contain just "int field;"; I've changed it so
that reads from the struct still work, but writes to "field" will cause
a compiler diagnostic (with writes to "field_writable" working fine).
I'd like to make sure that this works correctly; some people I've been
talking to (as well as me, to some extent) have been concerned that this
might potentially caused undefined behaviour in situations like this:
int function(struct some_struct *s)
{
int x = s->field;
s->field_writable--;
return x - s->field;
}
Based on the draft of the C11 standard I have access to (N1570.pdf; is
that the right one to be using?), this seems to not run afoul of 6.5.7
(which describes aliasing restrictions):
"An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:
[...]
- a qualified version of a type compatible with 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)
[...]"
However, I'm having problems determining exactly what the object that is
accessed is. Is it the struct as a whole? The individual union? One of
the fields of the union, and if so, which?
Other parts of the standard which might disallow this sort of thing are
6.5.16.1 (which governs the rules for what can be assigned to by what,
but does not seem by itself to disallow assignment even to a const field
of a union); and 6.7.3.6, which defines what "const" means, and
disallows assigning to a const object through a non-const type, but
again leaves it unclear precisely which object it is that's being
modified.
I feel like I'm missing something, especially because nothing I can
see in the rules I've mentioned disallows the following code:
int main(void)
{
const int c;
c = 0;
return c;
}
which is clearly not intended to be strictly conforming. Thus, I feel
I've missed a rule or two about what I can do with const types.
So, in short, what I'm wondering about is, does this union idiom for
making a partially const struct field do what I want? And why/why not?
I'm trying to maintain some existing code; in particular, there are some
struct fields that I suspect are being written directly rather than via
functions designed for the purpose. I'm trying to handle this with the
following idiom:
struct some_struct {
union {
const int field;
int field_writable;
};
}
Here, the struct used to contain just "int field;"; I've changed it so
that reads from the struct still work, but writes to "field" will cause
a compiler diagnostic (with writes to "field_writable" working fine).
I'd like to make sure that this works correctly; some people I've been
talking to (as well as me, to some extent) have been concerned that this
might potentially caused undefined behaviour in situations like this:
int function(struct some_struct *s)
{
int x = s->field;
s->field_writable--;
return x - s->field;
}
Based on the draft of the C11 standard I have access to (N1570.pdf; is
that the right one to be using?), this seems to not run afoul of 6.5.7
(which describes aliasing restrictions):
"An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:
[...]
- a qualified version of a type compatible with 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)
[...]"
However, I'm having problems determining exactly what the object that is
accessed is. Is it the struct as a whole? The individual union? One of
the fields of the union, and if so, which?
Other parts of the standard which might disallow this sort of thing are
6.5.16.1 (which governs the rules for what can be assigned to by what,
but does not seem by itself to disallow assignment even to a const field
of a union); and 6.7.3.6, which defines what "const" means, and
disallows assigning to a const object through a non-const type, but
again leaves it unclear precisely which object it is that's being
modified.
I feel like I'm missing something, especially because nothing I can
see in the rules I've mentioned disallows the following code:
int main(void)
{
const int c;
c = 0;
return c;
}
which is clearly not intended to be strictly conforming. Thus, I feel
I've missed a rule or two about what I can do with const types.
So, in short, what I'm wondering about is, does this union idiom for
making a partially const struct field do what I want? And why/why not?