6

I wrote some thing similar to this in my code

const int x=1;
int *ptr;
ptr = &x;
*ptr = 2;

Does this work on all compilers? Why doesn't the GCC compiler notice that we are changing a constant variable?

8
  • 1
    It does. You should get a message like warning: assignment discards qualifiers from pointer target type, referring to the line ptr = &x;. Commented Mar 22, 2013 at 17:03
  • 1
    This has some info too: stackoverflow.com/questions/945640/… Commented Mar 22, 2013 at 17:04
  • 1
    Hypothetically, a compiler could put a const int into read-only memory. Then *ptr = 2; would crash. De facto, don't expect it to crash. Oh, and the compiler will complain about discarding the qualifier on ptr = &x; if you let it. Commented Mar 22, 2013 at 17:06
  • My compiler declares an error ptr = &x; incompatible types 'int *' and 'const int * Commented Mar 22, 2013 at 17:29
  • 1
    @BillHicks And I once was stabbed with a knife but didn't die... does that prove that stabbings aren't fatal? Commented Mar 22, 2013 at 17:36

4 Answers 4

11

const actually doesn't mean "constant". Something that's "constant" in C has a value that's determined at compile time; a literal 42 is an example. The const keyword really means read-only. Consider, for example:

const int r = rand();

The value of r is not determined until program execution time, but the const keyword means that you're not permitted to modify r after it's been initialized.

In your code:

const int x=1;
int *ptr;
ptr = &x;
*ptr = 2;

the assignment ptr = &x; is a constraint violation, meaning that a conforming compiler is required to complain about it; you can't legally assign a const int* (pointer to const int) value to a non-const int* object. If the compiler generates an executable (which it needn't do; it could just reject it), then the behavior is not defined by the C standard.

For example, the generated code might actually store the value 2 in x -- but then a later reference to x might yield the value 1, because the compiler knows that x can't have been modified after its initialization. And it knows that because you told it so, by defining x as const. If you lie to the compiler, the consequences can be arbitrarily bad.

Actually, the worst thing that can happen is that the program behaves as you expect it to; that means you have a bug that's very difficult to detect. (But the diagnostic you should have gotten will have been a large clue.)

Sign up to request clarification or add additional context in comments.

13 Comments

Standard reference: C11 6.5.4/3
This compiler allows such a statement: int *ptr = (int*)&x; but not int *ptr = &x;. Additionally, printf("%d %d",x,*ptr); outputs the result 1 2 while printf("%p %p",&x, ptr); outputs the same address for both &x and ptr (something like 0x7ffe6a1aa47c). Is that counted as mistake/ bug or does it serve a purpose? Is that behavior language-related or compiler-related?
@Xfce4 I'd count int *ptr = (int*)&x; as a mistake by the programmer. I'd expect most C compilers to accept it without complaint (no diagnostic is required). The cast means that the conversion is not a constraint violation, but it does have undefined behavior. Given const int x = 1;, the compiler may legitimately assume that x continues to have the value 1, and need not generate code to read it again. If you go behind the compiler's back to write 2 to that memory location, you've lied to the compiler and it will get its revenge.
@Xfce4 The values and addresses are stored straightforwardly. What's not straightforward is that the compiler knows that x was defined with const, so it assumes its value cannot change, so it replaces the reference to x with the equivalent of a literal 1. This is a perfectly valid optimization. It gives unexpected results here because the programmer cheated.
@Xfce4 I thought I answered that. The implementation's obligation is to produce the defined behavior of the program. Any code it generates is just a means to that end. (And if the program has undefined behavior, all bets are off.)
|
4

Online C 2011 draft:

6.7.3 Type qualifiers

...
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. 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.133)
133) This applies to those objects that behave as if they were defined with qualified types, even if they are never actually defined as objects in the program (such as an object at a memory-mapped input/output address).

Emphasis added.

Since the behavior is left undefined, the compiler is not required to issue a diagnostic, nor is it required to halt translation. This would be difficult to catch in the general case; suppose you had a function like

void foo( int *p ) { *p = ...; }

defined in it's own separate translation unit. During translation, the compiler has no way of knowing if p could be pointing to a const-qualified object or not. If your call is something like

const int x;
foo( &x );

you may get a warning like parameter 1 of 'foo' discards qualifiers or something similarly illuminating.

Also note that the const qualifier doesn't necessarily mean that the associated variable will be stored in read-only memory, so it's possible the above code would "work" (update the value in x) in that you'd successfully update x by doing an end-run around the const semantics. But then you might as well just not declare x to be const.

1 Comment

It would be good to also mention that OP's code is a constraint violation, before we get so far as 6.7.3/6. (the reference is C11 6.5.4/3)
-1

There is a good discussion of this here:Does the evil cast get trumped by the evil compiler?

I would expect gcc to compile this because:

  • ptr is allowed to point to x, otherwise reading it would be impossible, although as the comment below says it's not exactly brilliant code and the compiler should complain. Warning options will (I guess) affect whether or not it's actually warned about.
  • when you write to x, the compiler no longer "knows" that it is writing to a const, all this is in the coders hands in C. However, it does really know, so it may well warn you, depending on the warning options you've selected.

whether it works or not, however, will depend on how the code is compiled, the way const is implemented for the compile options selected and the target CPU and architecture. It may work. Or it may crash. Or you may write to a "random" bit of memory and cause (or not) some freaky effect. It's not a good coding strategy, but that wasn't your question :-)

1 Comment

ptr isn't allowed to point to x; the compiler should (and does) complain. You would need const int *ptr for the assignment to be valid.
-1

Bad programmer. No Moon Pie!

If you need to modify a const, copy it to a non-const variable and then work with it. It's const for a reason. Trying to "sneak" around a const can cause serious runtime issues. i.e. the optimizer has likely used the value inline, etc.

const int x=1;
int non_const_x = x;
non_const_x = 2;

1 Comment

If you need to modify a const (not constant) object, don't define it as const in the first place.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.