繁体   English   中英

C/C++ 更改 const 的值

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

我有一篇文章,但我把它弄丢了。 它展示并描述了一些人们应该小心的 C/C++ 技巧。 其中一个让我感兴趣,但现在我试图复制它,我无法将它编译。

这个概念是可以偶然改变 C/C++ 中const的值

是这样的:

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

我想把这个给朋友看,但现在我错过了一步。 有谁知道开始编译和工作缺少什么?

ATM 我从 'const int*' 到 'int*' 的转换无效,但是当我阅读这篇文章时,我尝试过并且效果很好。

你需要抛弃常量:

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

常见的答案在 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 ~ $

顺便说一句..这绝不是推荐的...我发现 g++ 不允许这种情况发生..所以这可能是您遇到的问题。

只是一个猜测,但一个常见的问题是为什么不能将int**转换为const int** ,这乍一看似乎是合理的(毕竟,您只是添加一个const ,这通常是可以的) . 原因是如果你可以这样做,你可能会不小心修改一个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

这是一个非常不直观的结果,但在这种情况下确保您不能修改const object 的唯一方法(注意如何没有类型转换)是使第 3 行出错。

您只能在 FIRST 间接级别添加const而不进行强制转换:

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

在 C++ 中,如果不使用某种类型转换,就不可能修改const object。 您必须使用 C 风格的强制转换或 C++ 风格的const_cast来删除const -ness。 任何其他这样做的尝试都会在某处导致编译器错误。

请注意,标准未定义任何抛弃 constness 的尝试。 从标准的 7.1.5.1 开始:

除了可以修改声明为 mutable 的任何 class 成员之外,任何在其生命周期内修改 const object 的尝试都会导致未定义的行为。

在使用此示例之后:

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

所以简而言之,使用标准 C++ 无法实现您想要做的事情。

此外,当编译器遇到类似的声明时

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

可以自由地将任何出现的 'a' 替换为 3 (有效地做与#define a 3相同的事情)

回到时间的迷雾中,我们古程序员使用 FORTRAN。 FORTRAN 通过引用传递了它的所有参数,并且没有做任何类型检查。 这意味着即使是字面常量也很容易意外更改值。 您可以将“3”传递给 SUBROUTINE,它会返回更改,因此从那时起,您的代码每次都有“3”,它实际上就像一个不同的值。 让我告诉你,这些是很难找到和修复的错误。

你试过这个吗?

ptr = const_cast<int *>(ptr_to_a);

这应该有助于它编译,但由于演员阵容,这并不是偶然的。

在 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 */

在C中,一个const变量可以通过它的指针来修改; 然而,这是未定义的行为。 const 变量永远不能用作数组声明中的长度。

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

如果其值大于 0,则纯整数 const 变量可用作数组声明中的长度。

纯常量表达式由以下操作数组成。

  1. 数字文字(常量),例如 2, 10.53

  2. #define 指令定义的符号常量

  3. 枚举常量

  4. 纯 const 变量,即本身使用纯常量表达式初始化的 const 变量。

  5. 不允许使用非常量变量或易失变量。

我们可以通过以下代码更改 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;  
}

我正在寻找如何在 const 之间进行转换,我发现这个http://www.possibility.com/Cpp/const.html也许它对某人有用。 :)

我已经测试了下面的代码,它成功地更改了常量成员变量。

#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;
}

控制台 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 . . .

在这里,障碍是,您必须定义与您拥有的常量成员变量一样多的指针。

这将产生运行时错误。 因为intstatic 未处理的异常。 访问冲突写入位置 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;
}

最终解决方案:它将更改const变量的值;

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

您可能想使用 const_cast:

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

我不是 100% 确定这会起作用,但我对 C/C++ 有点生疏:-)

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;

您正在查看的文章可能一直在谈论两者之间的区别

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

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

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

或者我记得——我这里除了 Java 工具之外什么都没有,所以无法测试:)

其中一些答案指出,编译器可以优化掉变量 'a',因为它被声明为const 如果您真的希望能够更改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

当然,将某些东西声明为const volatile应该真正说明这是多么愚蠢。

您缺少的步骤是您不需要 int* 指针。 该行:

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

实际上说你不会改变ptr_to_a,而不是a。 因此,如果您将代码更改为如下所示:

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 现在是 5。您可以通过 ptr_to_a 更改 a 而不会发出任何警告。

编辑:

以上是不正确的。 事实证明,我将类似的技巧与 shared_ptr 混淆了,您可以在其中访问原始指针并修改内部数据值而不会触发任何警告。 那是:

#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;
}

将产生5。

暂无
暂无

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

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