【问题标题】:How to modify value of const variable? [duplicate]如何修改 const 变量的值? [复制]
【发布时间】:2012-08-24 07:19:47
【问题描述】:

我可以在 gcc 中更改 const 修改变量的值,但不能在其他编译器中更改。 我在 gcc 上尝试过这段代码,它更新了 ij (11) 的值。使用an online compiler,我得到不同的值。

#include<stdio.h>
void main() {
  const int i=10;
  int *j;
  j = &i;
  (*j)++;
  printf("address of j is %p address of i is %p\n",j,&i);
  printf("i is %d and j is %d\n",i,*j);
}

【问题讨论】:

  • 那是实际代码吗? IIRC 'j = &i' 实际上不应该编译。
  • @TomTanner:这是违反约束的,需要诊断。就标准而言,非致命警告就足够了。
  • 这和问“我买了一张单程票,我怎么用这张票回家?”是一回事。致电任何一家航空公司并询问该问题,然后您将得到同样适用于您的编程问题的答案。
  • @Lundin:太好了。另一家将我列入黑名单的公司。谢谢!
  • -pedantic-errors 和 gcc 不会让您编译标准要求诊断的东西,包括void main

标签: c gcc constants


【解决方案1】:

是的,你可以通过一些小技巧来做到这一点。

#include <stdio.h>
int main(){
    const int a = 0;
    *(int *)&a = 39;
    printf("%d", a);
}

在上面的代码中,a 是一个const int。使用小技巧,您可以更改常量值。

更新:说明

在上面的代码中,a 被定义为const。例如,a 有一个内存地址 0x01,因此 &amp;a 返回相同。当它用(int *) 强制转换时,它变成另一个变量,称为指向 const 的指针。当再次使用* 访问它时,另一个变量可以在不违反 const 策略的情况下被访问,因为它不是原始变量,但是由于它被称为指针的地址,所以更改会被反映。

这将适用于 Borland C++ 或 Turbo C++ 等旧版本,但是现在没有人使用它。

这是“未定义的行为”,这意味着根据标准,您无法预测尝试此操作时会发生什么。根据特定的机器、编译器和程序的状态,它可能会做不同的事情。

在这种情况下,最常见的情况是答案是“是”。变量,无论是否为 const,只是内存中的一个位置,您可以打破 const 的规则并简单地覆盖它。 (当然,如果程序的某些其他部分依赖于其 const 数据是常量,这将导致严重的错误!)

但是,在某些情况下——最常见的是 const 静态数据——编译器可能会将这些变量放在内存的只读区域中。比如 MSVC,通常会将 const static ints 放在可执行文件的 .text 段中,这意味着如果你试图写入它,操作系统会抛出一个保护错误,程序会崩溃。

在编译器和机器的其他组合中,可能会发生完全不同的事情。您可以确定的一件事是,这种模式会惹恼任何必须阅读您的代码的人。

试试这个并告诉我。

【讨论】:

  • 不解释 (a) 这是一个坏主意,并且 (b) 它不一定会起作用(行为未定义),而仅仅展示如何做这不是一个好主意。跨度>
  • @KeithThompson 我发布了解释。谢谢。它不适用于 gcc,但适用于 Borland 和 Turbo 版本的 C/C++。
  • 这在 .NET 中不起作用
  • @Nickal 这个问题被标记为 c 语言
  • 我说的是 .NET 中的 C。该问题未标记为g++linux
【解决方案2】:

如何修改const变量的值?

不!您不应修改 const 变量。
拥有const 变量的全部意义在于无法修改它。如果您想要一个应该能够修改的变量,只需不要在其上添加 const 限定符。

任何通过(指针)hackery 强行修改const 的代码都会调用Undefined Behavior

未定义行为意味着代码不符合 C 标准制定的标准规范,因此不是有效代码。这样的代码可以显示任何行为并且允许这样做。

【讨论】:

  • 绝对!永远不要更改 const 变量。在某些嵌入式系统上,const 变量存储在闪存而不是 RAM 上,因此无法更改。
  • const int r = rand(); 不会存储在闪存中。 const 不是“恒定”的意思,而是“只读”的意思。
  • 没错,你在大多数情况下所说的,尤其是在高级语言中。但是当在低级/嵌入式系统上工作时,您确实受到内存(RAM)的限制,您最好将大块数组保存在闪存中,并在需要时复制到 RAM 中。在这种极端情况下,指针黑客方法是为大多数其他重要计算节省 RAM 的大救星。
  • @YoTengoUnLCD :答案是UB,它可以显示任何行为,这就是答案所说的。您认为如何回答这个问题?
  • @YoTengoUnLCD 告诉别人如何编写无效代码没有任何目的。向他们解释为什么不应该这样做确实是有目的的。这可以类比,如果一个人问如何从桥上跳下来,你不告诉他们怎么做,你告诉他们如果你这样做你会死,所以放弃这个想法。
【解决方案3】:

通过将i 定义为const,您承诺不会修改它。编译器可以依赖该承诺并假设它没有被修改。当您打印i 的值时,编译器可以只打印10,而不是加载当前存储在i 中的任何值。

或者它可以选择加载值。或者,当您尝试修改i 时,它可能会导致您的程序崩溃。行为未定义。

根据优化选项(-O1-O3),您可能会看到 gcc 的不同行为。

哦,void main() 不正确;它应该是int main(void)。如果你的教科书告诉你使用void main(),你应该得到一本更好的书。

【讨论】:

    【解决方案4】:

    看看Can we change the value of an object defined with const through pointers?

    长话短说,它是undefined behaviour。它的结果可能取决于编译器/机器。

    【讨论】:

      【解决方案5】:

      你不能修改const变量的值,如果你在gcc中编译这段代码会显示

      error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]
      

      并显示未定义的行为

      主要是我们只能修改变量,当我们可以访问没有地址的地址时我们无能为力。 Register 存储类也是如此。

      【讨论】:

        猜你喜欢
        • 2015-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多