0

I thought that the & operator wouldn't work for constants because I thought their invokations are replaced with their values at compile time like with macros and that they're rvalues. I wrote this test and the output suprised me.

#include<stdio.h>
int main(void){
    const int a=1;
    *(int*)&a=2;
    printf("%i%i",a,*&a);
    return 0;
}

It outputs 12. I expected it to be 11. Thanks for reaching out.

markoj
  • 150
  • 10
  • 2
    If you invoke undefined behaviour by bludgeoning the compiler into accepting your code with casts, you get what you get. If you removed the cast, the code would not compile. – Jonathan Leffler Jul 27 '22 at 19:29
  • Surely you expected `22`? It outputs `11` without that line. – Weather Vane Jul 27 '22 at 19:32
  • 1
    Actually no, I thought that it would behave like the address is somehow read-only. – markoj Jul 27 '22 at 19:34
  • 3
    On a side note, there are no extra taxes or fees for using whitespace in your program and its output. Why not make it easier on yourself, and readers of this question, by using `printf("%i %i",a,*&a);`? – Steve Summit Jul 27 '22 at 20:17
  • In this situation it doesn't matter one way or the other because not both of the numbers have more than one digit. – markoj Jul 27 '22 at 20:23
  • 3
    @markoj Suit yourself. I, at least, found it confusing and annoying. – Steve Summit Jul 27 '22 at 20:47
  • If I make the constant `register`, the code wouldn't compile. – markoj Jul 30 '22 at 10:01

2 Answers2

2

It outputs 12. I expected it to be 11.

Incorrect expectations.


Casting a pointer to const data to a pointer to non-const data is OK - if the resulting pointer is not used to write data.

const int a=1;
(int*)&a; // OK 

Attempting to write via a pointer that originated as a pointer to const data is undefined behavior (UB). Don't code like that. Anything may happen.

*(int*)&a = ... // Not OK 

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. C17dr § 6.7.3 7

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I think that taking a `&` of a constant shouldn't be allowed because I think it's not needed unless you want to change its value. Is there a compiler that doesn't allow that? – markoj Jul 27 '22 at 20:43
  • Care to add a reference to your UB claim? I guess it'd improve the answer overall – Wilk Maia Jul 27 '22 at 20:50
  • 1
    @markoj "... because I think it's not needed unless you want to change its value" is incorrect. Some code uses/returns pointers to the object and not the object itself with always writing the object. – chux - Reinstate Monica Jul 27 '22 at 20:50
  • @WilkMaia Do you have access to the C spec? – chux - Reinstate Monica Jul 27 '22 at 20:52
  • @WilkMaia Search for "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" – chux - Reinstate Monica Jul 27 '22 at 20:54
  • @chux-ReinstateMonica, yep. I didn't mean it for my benefit. It was a suggestion to improve the answer :) – Wilk Maia Jul 27 '22 at 21:07
  • FYI if you wanna link ~the spec~ some drafts: https://stackoverflow.com/a/17015061/2853886 – Wilk Maia Jul 27 '22 at 21:09
  • You're right, @chux-ReinstateMonica. For example, when using a number of an optional size a function can require `void*` and `size_t` instead. An equivalent situation happened to me some time ago. Thanks. – markoj Jul 28 '22 at 08:42
-2

Check out the significance of the volatile keyword below.

Two identical functions, except that TrialB has keyword volatile, and TrialA does not.

TrialA outputs 11, because the compiler believes that variable a is const and cannot change.

TrialB outputs 22, because despite being declared const, the variable is also volatile and therefore needs to be re-examined on every use.

#include<stdio.h>

void TrialA(void)
{
    const int a=1;
    *(int*)&a=2;   // I expected a Warning on this line!
                   // Along the lines of "incompatible typecast from "const int*" to "int*"
                   // But surprisingly, I do not see such a warning.
    printf("%i%i\n",a,*&a);
}

void TrialB(void)
{
    volatile const int a=1;
    *(int*)&a=2;
    printf("%i%i\n",a,*&a);
}


int main(void){
    TrialA();
    TrialB();
    return 0;
}

Output

Success #stdin #stdout 0s 5536KB
11
22
abelenky
  • 63,815
  • 23
  • 109
  • 159