24

I had an article, but I lost it. It showed and described a couple of C/C++ tricks that people should be careful. One of them interested me but now that I am trying to replicate it I'm not being able to put it to compile.

The concept was that it is possible to change by accident the value of a const in C/C++

It was something like this:

const int a = 3;          // I promise I won't change a
const int *ptr_to_a = &a; // I still promise I won't change a
int *ptr;
ptr = ptr_to_a;

(*ptr) = 5;               // I'm a liar; a is now 5

I wanted to show this to a friend but now I'm missing a step. Does anyone know what's missing for it to start compiling and working?

ATM I'm getting invalid conversion from 'const int*' to 'int*' but when I read the article I tried and it worked great.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
fmsf
  • 36,317
  • 49
  • 147
  • 195
  • I posted a complete program and explained that it's g++ that is blocking it, gcc allows this behavior. – sfossen Feb 24 '09 at 20:52
  • 2
    Even if you get it to compile. it is undefined behavior. It may blow up your computer, crash your program, or make demons fly out of your nose. Or, of course, it may appear to work. For now. On your machine. – jalf Nov 27 '09 at 09:46

18 Answers18

47

you need to cast away the constness:

linux ~ $ cat constTest.c
#include <stdio.h>


void modA( int *x )
{
        *x = 7;
}


int main( void )
{

        const int a = 3; // I promisse i won't change a
        int *ptr;
        ptr = (int*)( &a );

        printf( "A=%d\n", a );
        *ptr = 5; // I'm a liar, a is now 5
        printf( "A=%d\n", a );

        *((int*)(&a)) = 6;
        printf( "A=%d\n", a );

        modA( (int*)( &a ));
        printf( "A=%d\n", a );

        return 0;
}
linux ~ $ gcc constTest.c -o constTest
linux ~ $ ./constTest
A=3
A=5
A=6
A=7
linux ~ $ g++ constTest.c -o constTest
linux ~ $ ./constTest
A=3
A=3
A=3
A=3

also the common answer doesn't work in g++ 4.1.2

linux ~ $ cat constTest2.cpp
#include <iostream>
using namespace std;
int main( void )
{
        const int a = 3; // I promisse i won't change a
        int *ptr;
        ptr = const_cast<int*>( &a );

        cout << "A=" << a << endl;
        *ptr = 5; // I'm a liar, a is now 5
        cout << "A=" << a << endl;

        return 0;
}
linux ~ $ g++ constTest2.cpp -o constTest2
linux ~ $ ./constTest2
A=3
A=3
linux ~ $

btw.. this is never recommended... I found that g++ doesn't allow this to happen.. so that may be the issue you are experiencing.

sfossen
  • 4,774
  • 24
  • 18
13

Note any attempt to cast away constness is undefined by the standard. From 7.1.5.1 of the standard:

Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

And right after this example is used:

const int* ciq = new const int (3);     //  initialized as required
int* iq = const_cast<int*>(ciq);        //  cast required
*iq = 4;                                //  undefined: modifies a  const  object

So in short what you want to do isn't possible using standard C++.

Further when the compiler encounters a declaration like

const int a = 3; // I promisse i won't change a

it is free to replace any occurance of 'a' with 3 (effectively doing the same thing as #define a 3)

Andrew Khosravian
  • 1,069
  • 6
  • 13
12

Just a guess, but a common question is why one can't convert an int** to a const int**, which at first appears to be reasonable (after all, you're just adding a const, which is normally ok). The reason is that if you could do this, you could accidentally modify a const object:

const int x = 3;
int *px;
const int **ppx = &px;  // ERROR: conversion from 'int**' to 'const int**'
*ppx = &x;  // ok, assigning 'const int*' to 'const int*'
*px = 4;    // oops, just modified a const object

It's a very non-intuitive result, but the only way to make sure that you can't modify a const object in this case (note how there are no typecasts) is to make line 3 an error.

You're only allowed to add const without a cast at the FIRST level of indirection:

int * const *ppx = &px;  // this is ok
*ppx = &x;               // but now this is an error because *ppx is 'const'

In C++, it is impossible to modify a const object without using a typecast of some sort. You'll have to use either a C-style cast or a C++-style const_cast to remove the const-ness. Any other attempt to do so will result in a compiler error somewhere.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
11

Back in the mists of time, we paleo-programmers used FORTRAN. FORTRAN passed all its parameters by reference, and didn't do any typechecking. This meant it was quite easy to accidentally change the value of even a literal constant. You could pass "3" to a SUBROUTINE, and it would come back changed, and so every time from then on where your code had a "3", it would actually act like a different value. Let me tell you, those were hard bugs to find and fix.

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
4

Did you try this?

ptr = const_cast<int *>(ptr_to_a);

That should help it compile but it's not really by accident due to the cast.

Michael Kristofik
  • 34,290
  • 15
  • 75
  • 125
2

In C++, Using Microsoft Visual Studio-2008

const int a = 3;    /* I promisse i won't change a */
int * ptr1  = const_cast<int*> (&a);
*ptr1 = 5;  /* I'm a liar, a is now 5 . It's not okay. */
cout << "a = " << a << "\n"; /* prints 3 */
int arr1[a]; /* arr1 is an array of 3 ints */

int temp = 2;
/* or, const volatile int temp = 2; */
const int b = temp + 1; /* I promisse i won't change b */
int * ptr2  = const_cast<int*> (&b);
*ptr2 = 5; /* I'm a liar, b is now 5 . It's okay. */
cout << "b = " << b << "\n"; /* prints 5 */
//int arr2[b]; /* Compilation error */

In C, a const variable can be modified through its pointer; however it is undefined behavior. A const variable can be never used as length in an array declaration.

In C++, if a const variable is initialized with a pure constant expression, then its value cannot be modified through its pointer even after try to modify, otherwise a const variable can be modified through its pointer.

A pure integral const variable can be used as length in an array declaration, if its value is greater than 0.

A pure constant expression consists of the following operands.

  1. A numeric literal (constant ) e.g. 2, 10.53

  2. A symbolic constant defined by #define directive

  3. An Enumeration constant

  4. A pure const variable i.e. a const variable which is itself initialized with a pure constant expression.

  5. Non-const variables or volatile variables are not allowed.

Mithilesh
  • 21
  • 2
1

this will create a runtime fault. Because the int is static. Unhandled exception. Access violation writing location 0x00035834.

void main(void)
{
    static const int x = 5;
    int *p = (int *)x;
    *p = 99;                //here it will trigger the fault at run time
}
joexxxz
  • 11
  • 3
1

Some of these answers point out that the compiler can optimize away the variable 'a' since it is declared const. If you really want to be able to change the value of a then you need to mark it as volatile

  const volatile int a = 3; // I promise i won't change a
  int *ptr = (int *)&a;
  (*ptr) = 5; // I'm a liar, a is now 5

Of course, declaring something as const volatile should really illustrate just how silly this is.

pk.
  • 420
  • 2
  • 6
  • I do not think that word ("volatile") means what you think it means. It has nothing to do with whether you can change the value, but rather insures that a read or write in the source code is made a read or write in the executable, one for one. In other words, no caching. – David Thornley Feb 24 '09 at 21:03
  • That's what i was getting at. The compiler will see const and optimize the value away. Whereas if you declare it volatile, it cannot since like you said 'no caching'. – pk. Mar 08 '09 at 18:41
0
#include<iostream>
int main( void )
{
   int i = 3;    
   const int *pi = &i;
   int *pj = (int*)&i;
    *pj = 4;

   getchar(); 
   return 0;  
}
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
manoj
  • 1
0

I was looking on how to convert between consts and I found this one http://www.possibility.com/Cpp/const.html maybe it can be useful to someone. :)

CompuPlanet
  • 151
  • 1
  • 11
0

I have tested the code below and it successfully changes the constant member variables.

#include <iostream>

class A
{
    private:
        int * pc1;  // These must stay on the top of the constant member variables.
        int * pc2;  // Because, they must be initialized first
        int * pc3;  // in the constructor initialization list.
    public:
        A() : c1(0), c2(0), c3(0), v1(0), v2(0), v3(0) {}
        A(const A & other)
            :   pc1 (const_cast<int*>(&other.c1)),
                pc2 (const_cast<int*>(&other.c2)),
                pc3 (const_cast<int*>(&other.c3)),
                c1  (*pc1),
                c2  (*pc2),
                c3  (*pc3),
                v1  (other.v1),
                v2  (other.v2),
                v3  (other.v3)
        {
        }
        A(int c11, int c22, int c33, int v11, int v22, int v33) : c1(c11), c2(c22), c3(c33), v1(v11), v2(v22), v3(v33)
        {
        }
        const A & operator=(const A & Rhs)
        {
            pc1     =  const_cast<int*>(&c1);
            pc2     =  const_cast<int*>(&c2),
            pc3     =  const_cast<int*>(&c3),
            *pc1    = *const_cast<int*>(&Rhs.c1);
            *pc2    = *const_cast<int*>(&Rhs.c2);
            *pc3    = *const_cast<int*>(&Rhs.c3);
            v1      = Rhs.v1;
            v2      = Rhs.v2;
            v3      = Rhs.v3;
            return *this;
        }
        const int c1;
        const int c2;
        const int c3;
        int v1;
        int v2;
        int v3;
};

std::wostream & operator<<(std::wostream & os, const A & a)
{
    os << a.c1 << '\t' << a.c2 << '\t' << a.c3 << '\t' << a.v1 << '\t' << a.v2 << '\t' << a.v3 << std::endl;
    return os;
}

int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
    A ObjA(10, 20, 30, 11, 22, 33);
    A ObjB(40, 50, 60, 44, 55, 66);
    A ObjC(70, 80, 90, 77, 88, 99);
    A ObjD(ObjA);
    ObjB = ObjC;
    std::wcout << ObjA << ObjB << ObjC << ObjD;

    system("pause");
    return 0;
}

The console output is:

10      20      30      11      22      33
70      80      90      77      88      99
70      80      90      77      88      99
10      20      30      11      22      33
Press any key to continue . . .

Here, the handicap is, you have to define as many pointers as number of constant member variables you have.

hkBattousai
  • 10,583
  • 18
  • 76
  • 124
0

You probably want to use const_cast:

int *ptr = const_cast<int*>(ptr_to_a);

I'm not 100% certain this will work though, I'm a bit rusty at C/C++ :-)

Some readup for const_cast: http://msdn.microsoft.com/en-us/library/bz6at95h(VS.80).aspx

0
const int foo = 42;
const int *pfoo = &foo;
const void *t = pfoo;
void *s = &t; // pointer to pointer to int
int **z = (int **)s; // pointer to int
**z = 0;
dirkgently
  • 108,024
  • 16
  • 131
  • 187
0

The article you were looking at might have been talking about the difference between

const int *pciCantChangeTarget;
const int ci = 37;
pciCantChangeTarget = &ci; // works fine
*pciCantChangeTarget = 3; // compile error

and

int nFirst = 1;
int const *cpiCantChangePointerValue = &nFirst;
int nSecond = 968;

*pciCantChangePointerValue = 402; // works
cpiCantChangePointerValue = &ci; // compile error

Or so I recall-- I don't have anything but Java tools here, so can't test :)

mjfgates
  • 3,351
  • 1
  • 18
  • 15
-1

we can change the const variable value by the following code :

const int x=5; 

printf("\nValue of x=%d",x);

*(int *)&x=7;

printf("\nNew value of x=%d",x);
kleopatra
  • 51,061
  • 28
  • 99
  • 211
Aryan
  • 143
  • 1
  • 3
-1
#include<stdio.h>
#include<stdlib.h>

int main(void) {
    const int a = 1; //a is constant
    fprintf(stdout,"%d\n",a);//prints 1
    int* a_ptr = &a;
    *a_ptr = 4;//memory leak in c(value of a changed)
    fprintf(stdout,"%d",a);//prints 4
return 0;
}
-1

Final Solution: it will change const variable a value;

cont int a = 10;
*(int*)&a= 5; // now a prints 5
// works fine.
barbsan
  • 3,418
  • 11
  • 21
  • 28
-2

The step you're missing is that you don't need the int* pointer. The line:

const int *ptr_to_a = &a; // I still promiss i won't change a;

actually says you won't change ptr_to_a, not a. So if you changed your code to read like this:

const int a = 3; // I promise I won't change a
const int *ptr_to_a = &a; // I promise I won't change ptr_to_a, not a.

(*ptr_to_a) = 5; // a is now 5

a is now 5. You can change a through ptr_to_a without any warning.

EDIT:

The above is incorrect. It turns out I was confusing a similar trick with a shared_ptr, in which you can get access to the raw pointer and modify the internal data value without firing off any warnings. That is:

#include <iostream>
#include <boost/shared_ptr.hpp>

int main()
{
    const boost::shared_ptr<int>* a = new boost::shared_ptr<int>(new int(3));
    *(a->get()) = 5;
    std::cout << "A is: " << *(a->get()) << std::endl;

    return 0;
}

Will produce 5.

jasedit
  • 662
  • 4
  • 10
  • that doesn't compile for sure "error: assignment of read-only location" – fmsf Feb 24 '09 at 19:14
  • No, ptr_to_a is a pointer to const int, meaning exactly that you promise not to change a. – Michael Kristofik Feb 24 '09 at 19:22
  • Yeah - I know I've run into this trick before, but it's some variation on this. I'm trying to dig through code and figure out the variant I've seen. – jasedit Feb 24 '09 at 19:22
  • The boost thing is a non-trick too. `const shared_ptr a(new int(3)); *a = 5;` works just as well. The stored pointer itself is not constant. Try modifying a `shared_ptr` instead. – UncleBens Jul 22 '11 at 19:03