0

I am confused as to what ANSI specification says about changing a variable declared const can be legally modified through its address. Unfortunately I do not have access to C90 specification but got conflicting pointers:

  1. The keyword const doesn't turn a variable into a constant! A symbol with the const qualifier merely means that the symbol cannot be used for assignment. This makes the value re ad -onl y through that symbol; it does not prevent the value from being modified through some other means internal (or even external) to the program. It is pretty much useful only for qualifying a pointer parameter, to indicate that this function will not change the data that argument points to, but other functions may. (Expert C Programming: Deep C Secrets: Peter van der Linden)

  2. If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined. (http://flash-gordon.me.uk/ansi.c.txt)

I have seen the latter in C99 specification (n1256.pdf).

Can anyone clarify as to which of the above two views is true please?

Edit: The Expect C Programming actually gives an example to demonstrate the ability to change a const variable using pointer.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Quiescent
  • 1,088
  • 7
  • 18
  • 2
    Why cannot they both be true? The first one is saying that const variables may be changed through external means. The second one is saying that attempting to do this intentionally is undefined behavior, as far as I understand it. – Andon M. Coleman Sep 12 '13 at 08:48
  • Language constructs are meant to protect against accidental misuse, not intentional misuse - I am trying to convince people about the same thing in this question - http://stackoverflow.com/questions/18755713/how-does-final-play-a-role-in-security - most people seem to think language constructs can be used to enforce security or prevent intentional misuse. Thankfully, that Q has now been closed as dup of a another question which has saner answers. – user93353 Sep 12 '13 at 08:53

6 Answers6

3

Don't know about C90, but C11 contains this clause, which I imagine has been there since day one (C11, 6.7.3/6):

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.

The same is true for volatile-qualified objects.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Yes, it appears to be there from the beginning. But I wonder how could such a good book put it right under the heading, _Reading the ANSI C Standard for Fun, Pleasure, and Profit_? – Quiescent Sep 12 '13 at 08:52
  • @user926918: there's no contradiction in the two quotes you put in your question, so I'm not sure I understand your comment. – Mat Sep 12 '13 at 08:58
3

It's similar in C90(C89) as C99.

C89 §3.5.3 Type qualifiers

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.

Undefined behavior doesn't mean that C prohibits it at all, just the behavior is, well, not defined. So actually the two of your statements are both true.

Community
  • 1
  • 1
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • As far as the C standard is concerned, any program which triggers Undefined Behavior is *completely meaningless*. It's possible for a compiler vendor to assign meanings to programs whose meaning is not defined by the C standard, but I would consider a statement that certain constructs yield Undefined Behavior as being equivalent to a statement that they are forbidden on any compiler whose documentation does not explicitly provide for them. – supercat Sep 03 '14 at 21:14
  • @supercat To write correct and portable code, undefined behavior should always be avoided. But there are times when it's not possible to use portable code to solve specific problem. For example, on some embedded environment, the address `0` needs to be accessed. In portable code, it's illegal to do such things, but a compiler may allow you doing that on this specific platform. – Yu Hao Sep 04 '14 at 01:10
  • If a compiler's documentation says what will happen if code accesses `(int*)0`, then it's not forbidden *when using that compiler*. My point is that if the standard says a construct yields Undefined Behavior and one's compiler *doesn't* specify a behavior for it, such a construct must be considered forbidden if one wishes to write meaningful code. It would have been helpful if in many situations which presently invoke Undefined Behavior the Standards Committee had either specified a limited set of things that could happen, or at least specified that a compiler which would yield... – supercat Sep 04 '14 at 15:20
  • ...behavior outside the "expected" range of things that could happen must document that [e.g. specify that *absent documentation to the contrary*, an integer overflow will yield a unspecified indeterminate value which may be outside the normal range of a type, may change if read repeatedly, and may be a trap representation, but may not have any other effect unless the compiler documentation either specifies a particular effect or explicitly says that the behavior is totally undefined. Such a rule would be helpful in some situations where cross-checking the results of several computations... – supercat Sep 04 '14 at 15:33
  • ...would reveal that one was bogus, but where code wouldn't know which computation was bogus until all had been performed. Avoiding integer overflows in computations whose outcome isn't going to matter may add code complexity without real benefit. – supercat Sep 04 '14 at 15:39
1

It is logical that behavior is undefined if you try to modify const variable. Consider embedded platforms where code + constants are placed in ROM. In that case, it is simply not possible to change the value, as it is burnt in forever. Where as if everything resides in RAM, it will likely be changable. That is why the standard says "undefined behavior" in this case - the behaviour must be dependent on platform and compiler.

Statement 1 and 2 are not really mutually exclusive.

Johan Kotlinski
  • 25,185
  • 9
  • 78
  • 101
1

What a declaration such as:

T const *p; //p has type “pointer to const T

means?
A program can use the expression p to alter the value of the pointer object that p designates, but it can’t use the expression *p to alter the value of any objects that *p might designate. If the program has another expression e of unqualified type that designates an object that *p also designates, the program can still use e to change that object. Thus, a program might be able to change an object right out from under a const-qualified expression.

haccks
  • 104,019
  • 25
  • 176
  • 264
1

Change in const variable is possible using pointer because it is just a memory location so it will surely accepts the changes made by pointer method.

But since this variable was defined as const so changes in its value will invoke undefined behaviour.

Dayal rai
  • 6,548
  • 22
  • 29
1

What gave you the impression that these two statements were mutually exclusive?

const is just a type qualifier, it's nothing magical.

Memory can still be altered through external means, or through circumventing the compiler's ability to recognize type restrictions. The second statement merely says that attempting to do this will have undefined results; it may or may not change the value.

The way I see it, there is nothing contradictory about either statement.

Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106