【问题标题】:C -- Modify const through aliased non-const pointerC -- 通过别名非常量指针修改 const
【发布时间】:2015-09-22 01:28:14
【问题描述】:

标准 C 中是否允许函数使用别名 int * 修改以 const int * 给出的 int?换句话说,下面的代码是否保证在标准 C 中总是返回 42 和 1?

#include <stdio.h>

void foo(const int *a, int *b)
{
    printf("%d\n", *a);
    *b = 1;
    printf("%d\n", *a);
}

int main(void)
{
    int a = 42;
    foo(&a, &a);
    return 0;
}

【问题讨论】:

    标签: c constants compiler-optimization


    【解决方案1】:

    在您的示例代码中,您有一个整数。你拿一个指向它的 const 指针和一个指向它的非常量指针。当然,通过非常量指针修改整数是合法且定义明确的。

    由于两个指针都是指向整数的指针,并且 const 指针不需要指向 const 对象,那么编译器应该期望从 const 指针读取的值可能已经改变,并且是必需的重新加载值。

    请注意,如果您使用了 restrict 关键字,则情况并非如此,因为它指定指针参数不为任何其他指针参数设置别名,因此编译器可以优化重新加载。

    【讨论】:

    • 因为一些投票是基于其他答案的状态而不是他们的知识。 “逻辑”是这样的:因为有另一个被否决的答案是肯定的,所以我的答案也一定是不正确的。另一种解释是,某人完全是错误的,只是一个非常热心的选民。
    • 问这个问题的人在问这个问题后已经下降了 3 分,所以我猜他们投了反对票,如果你每次点击失去 1 分。
    • @DarrylMiles 什么?这和什么有什么关系?
    • 重新投票政策,因为我也想知道谁在没有任何评论的情况下对新答案投票?也许有人可以指出我关于这个的民间传说?它必须做这里的评论。
    • @DarrylMiles 人们总是以奇怪的方式投反对票(和投赞成票)。我不认为有任何可执行的政策,但如果你想要谣言,可以尝试搜索元数据。我最近读到一件有趣的事。释义:“看看你认为非常愚蠢的所有问题。现在意识到这样的问题表明有很大一部分用户可能乐于支持这些问题”。反对票也是如此。
    【解决方案2】:

    是的,是的。您的程序已定义。

    您使用指向 const int 的指针指向非 const int 变量这一事实不会使该变量成为 const,并且仍可以通过指向 int 的指针或使用原始变量标签进行修改。

    【讨论】:

      【解决方案3】:

      是的,你可以这样做(如果你知道你可以摆脱它)。

      您可能无法摆脱它的一个原因是,如果您正在写入的目标内存位于只读保护区(例如常量数据)中,那么您将遇到访问冲突。例如,在编译时任何 const 都以可执行文件的只读数据部分结尾。大多数平台都支持在运行时保护它不被写入。

      基本上不做。

      您的示例还存在其他问题,可能无法使其成为最佳演示。例如需要在第二个 printf 中重新加载 *a 编译器可能会优化它! (它知道'a'没有改变,它知道'a'指向一个const,因此,它不需要通过为第二个'*a'表达式执行内存加载来重新加载内存,它可以重用它可能的值从第一次加载'*a'开始就在一个寄存器中)。现在,如果您在两者之间添加一个内存屏障,那么您的示例就有机会更好地工作。

      https://en.wikipedia.org/wiki/Memory_barrier 海湾合作委员会? asm volatile ("" : : : "内存"); // 可能在第二个 printf 之前工作

      但是对于您提出的实际问题的负责人,是的,如果您知道自己对其他类似的事情在做什么,那么您就可以做到。

      【讨论】:

      • 任何优化重新加载的编译器,因为第二个 printf 属于垃圾箱。不需要屏障。 那么你的例子有机会做得更好。对此我只能说:???
      • 请引用禁止此类优化的规范。
      • 您在争论它可以优化它,因此您必须引用允许它的部分。 (当然这是不可能的。)
      • @DarrylMiles restrict 关键字的存在是为了允许这样的优化 - 这不是默认情况下允许发生的事情。
      • 也许你是对的,不能在 GCC 的快速测试中证明任何一种方式(无论有没有__restrict__),我一直在这样的优化是可能的基础上工作,因为'*b =1;'是编译器完全理解其副作用的表达式,因此 *a 已经被它第二次知道了。感谢您的信息。
      【解决方案4】:

      是的,保证总是打印 42 和 1。

      const int *a 表示指向的值是指针a 的常量。

      尝试从函数中的a*a = 10;)解引用,会报错。

      然而,指针a 不是常量。例如,您可以使用a = b

      b 可以指向与a 相同的地址和/或修改值,就像您在示例中所做的那样。 您是否将b 指针的值声明为常量(const int *b),您会收到错误消息。

      我尝试这样记忆:

      const int *a - a 指向一个 int 类型的对象,它不允许修改(任何其他指向该对象的指针都可以做它想做的事,取决于它的声明/定义)。

      【讨论】:

      • 您给出了正确的答案,但您的解释使用了不正确的术语。 (我没有投反对票)
      • 不用担心投反对票。就是这样。我很感兴趣,你的意思是什么术语不好?
      • 我明白了。没问题。 OP 根本不使用constants,所以我想没有混淆。
      • @Elyasin 在我们讨论要修复的问题时,"const int *a - a 指向 int 类型的只读对象" 不正确。它不必指向只读对象,尽管它可以这样做。只是对象不能通过 const 限定的指针进行修改。
      • @Elyasin Academic 与否,您编辑的版本要好得多。
      猜你喜欢
      • 2011-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多