Ben Bacarisse said:
[...]
That wasn't how I read it.
It would help if you could be a little more explicit in
saying just what interpretation you believe is actually
the case. I will start the ball rolling. The program
copx posted:
#include<stdio.h>
void foo(const int *c)
{
*((int *)c) = 'B';
}
int main(void)
{
int a = 'A';
foo(&a);
putchar(a);
return 0;
}
does _not_ have any undefined behavior. Do you dispute
that? If so, please cite those sections of the Standard
that support your view.
That code is in some kind of difficulty.
Can you explain what difficulty you see? Your choice of words suggests
that you agree that the code does not have any undefined behaviour.
Suppose foo's caller wants and expects the value retained (*&a)?
I don't see any problem with that.
A function takes an argument of type pointer to const
int, then modifies the int; and you do not see a problem?
No, I do not; such code has well-defined behavior according to the C
standard. I would expect that anyone writing such code probably knows
what that well-defined behavior is, and would probably write such code
only if that behavior was desired. Those 'probably's cover the
possibility that such code might have been written in error, but there's
little evidence that such an error was made.
In this simple example, the 'const' on the declaration of 'c' is not
merely pointless, but actually forces the otherwise unnecessary use of a
cast to remove it. In real world code, that would be a sign of poor
design, unless there were a good reason why '*c' had to be const. The
most obvious possibility would be because that was the signature
required for a call-back function that is part of a third-party library.
However, this is clearly not real world code, it serves only as an
example for purposes of discussing the fact that the C standard allows
such code.
The compact with the compiler works both ways. The
coder agrees to abide by the promises he makes; ...
As far as the C standard is concerned, the promise made when you declare
that a function is "const int *c", is that your code will do things like
*(int*)c = 'B' only if c is known to point to an object that is not
defined as const. Since the above code makes sure that foo() is only
called on &a, and since 'a' is not defined as const, there's no
violation of that promise.
... and
he expects the compiler to enforce the promises the
compiler makes: in this case to kick up a fuss when
the implementer of foo attempts to modify a const.
The only promise the standard requires of the compiler is to "raise a
fuss" if an attempt is made to write through such a pointer without
first explicitly converting it to a pointer to non-const. With such a
cast, no diagnostic is required.
No attempt was made to modify a object defined as const. 'a' is not a
const. The type of *(int*)c is not const-qualified, either. More
importantly, in this code, 'c' never points at any object other than
'a'. Therefore, *(int*)c does not refer to any object defined as const.
...
For another thing you excised the compiler warning.
It was only labeled as a warning; it was not a mandatory diagnostic. A
compiler can choose to warn you about anything it wants. It could warn
you not to compile programs on Friday the 13th. The fact that a warning
was issued is not relevant to the question of whether or not this code
has defined behavior.