简体   繁体   English

C/C++ 更改 const 的值

[英]C/C++ changing the value of a const

I had an article, but I lost it.我有一篇文章,但我把它弄丢了。 It showed and described a couple of C/C++ tricks that people should be careful.它展示并描述了一些人们应该小心的 C/C++ 技巧。 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++这个概念是可以偶然改变 C/C++ 中const的值

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. ATM 我从 'const int*' 到 'int*' 的转换无效,但是当我阅读这篇文章时,我尝试过并且效果很好。

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常见的答案在 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.顺便说一句..这绝不是推荐的...我发现 g++ 不允许这种情况发生..所以这可能是您遇到的问题。

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).只是一个猜测,但一个常见的问题是为什么不能将int**转换为const int** ,这乍一看似乎是合理的(毕竟,您只是添加一个const ,这通常是可以的) . The reason is that if you could do this, you could accidentally modify a const object:原因是如果你可以这样做,你可能会不小心修改一个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.这是一个非常不直观的结果,但在这种情况下确保您不能修改const object 的唯一方法(注意如何没有类型转换)是使第 3 行出错。

You're only allowed to add const without a cast at the FIRST level of indirection:您只能在 FIRST 间接级别添加const而不进行强制转换:

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.在 C++ 中,如果不使用某种类型转换,就不可能修改const object。 You'll have to use either a C-style cast or a C++-style const_cast to remove the const -ness.您必须使用 C 风格的强制转换或 C++ 风格的const_cast来删除const -ness。 Any other attempt to do so will result in a compiler error somewhere.任何其他这样做的尝试都会在某处导致编译器错误。

Note any attempt to cast away constness is undefined by the standard.请注意,标准未定义任何抛弃 constness 的尝试。 From 7.1.5.1 of the standard:从标准的 7.1.5.1 开始:

Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.除了可以修改声明为 mutable 的任何 class 成员之外,任何在其生命周期内修改 const object 的尝试都会导致未定义的行为。

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++.所以简而言之,使用标准 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 )可以自由地将任何出现的 'a' 替换为 3 (有效地做与#define a 3相同的事情)

Back in the mists of time, we paleo-programmers used FORTRAN.回到时间的迷雾中,我们古程序员使用 FORTRAN。 FORTRAN passed all its parameters by reference, and didn't do any typechecking. FORTRAN 通过引用传递了它的所有参数,并且没有做任何类型检查。 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.您可以将“3”传递给 SUBROUTINE,它会返回更改,因此从那时起,您的代码每次都有“3”,它实际上就像一个不同的值。 Let me tell you, those were hard bugs to find and fix.让我告诉你,这些是很难找到和修复的错误。

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.这应该有助于它编译,但由于演员阵容,这并不是偶然的。

In C++, Using Microsoft Visual Studio-2008在 C++ 中,使用 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;在C中,一个const变量可以通过它的指针来修改; however it is undefined behavior.然而,这是未定义的行为。 A const variable can be never used as length in an array declaration. const 变量永远不能用作数组声明中的长度。

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.在C++中,如果一个const变量用纯常量表达式初始化,那么即使尝试修改后也不能通过其指针修改其值,否则可以通过其指针修改const变量。

A pure integral const variable can be used as length in an array declaration, if its value is greater than 0.如果其值大于 0,则纯整数 const 变量可用作数组声明中的长度。

A pure constant expression consists of the following operands.纯常量表达式由以下操作数组成。

  1. A numeric literal (constant ) eg 2, 10.53数字文字(常量),例如 2, 10.53

  2. A symbolic constant defined by #define directive #define 指令定义的符号常量

  3. An Enumeration constant枚举常量

  4. A pure const variable ie a const variable which is itself initialized with a pure constant expression.纯 const 变量,即本身使用纯常量表达式初始化的 const 变量。

  5. Non-const variables or volatile variables are not allowed.不允许使用非常量变量或易失变量。

we can change the const variable value by the following code:我们可以通过以下代码更改 const 变量值:

const int x=5; 

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

*(int *)&x=7;

printf("\nNew value of x=%d",x);
#include<iostream>
int main( void )
{
   int i = 3;    
   const int *pi = &i;
   int *pj = (int*)&i;
    *pj = 4;

   getchar(); 
   return 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.我正在寻找如何在 const 之间进行转换,我发现这个http://www.possibility.com/Cpp/const.html也许它对某人有用。 :) :)

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:控制台 output 是:

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.在这里,障碍是,您必须定义与您拥有的常量成员变量一样多的指针。

this will create a runtime fault.这将产生运行时错误。 Because the int is static .因为intstatic Unhandled exception.未处理的异常。 Access violation writing location 0x00035834.访问冲突写入位置 0x00035834。

void main(void)
{
    static const int x = 5;
    int *p = (int *)x;
    *p = 99;                //here it will trigger the fault at run time
}
#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;
}

Final Solution: it will change const variable a value;最终解决方案:它将更改const变量的值;

cont int a = 10;
*(int*)&a= 5; // now a prints 5
// works fine.

You probably want to use const_cast:您可能想使用 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++:-)我不是 100% 确定这会起作用,但我对 C/C++ 有点生疏:-)

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

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;

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:)或者我记得——我这里除了 Java 工具之外什么都没有,所以无法测试:)

Some of these answers point out that the compiler can optimize away the variable 'a' since it is declared const .其中一些答案指出,编译器可以优化掉变量 'a',因为它被声明为const If you really want to be able to change the value of a then you need to mark it as volatile如果您真的希望能够更改a的值,那么您需要将其标记为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.当然,将某些东西声明为const volatile应该真正说明这是多么愚蠢。

The step you're missing is that you don't need the int* pointer.您缺少的步骤是您不需要 int* 指针。 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.实际上说你不会改变ptr_to_a,而不是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. a 现在是 5。您可以通过 ptr_to_a 更改 a 而不会发出任何警告。

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.事实证明,我将类似的技巧与 shared_ptr 混淆了,您可以在其中访问原始指针并修改内部数据值而不会触发任何警告。 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.将产生5。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM