【问题标题】:Why can I modify the const pointer in C?为什么我可以修改 C 中的 const 指针?
【发布时间】:2012-05-04 21:07:27
【问题描述】:

今天我尝试使用 const 标识符,但发现 const 变量仍然可以修改,这让我感到困惑..

以下是代码,在 compare(const void *a, const void *b) 函数中,我尝试修改 a 指向的值:

#include <stdio.h>
#include <stdlib.h>

int values[] = {40, 10, 100, 90, 20, 25};

int compare (const void *a, const void*b)
{
    *(int*)a=2;
/* Then the value that a points to will be changed! */
    return ( *(int*)a - *(int*)b);
}

int main ()
{
    int n;
    qsort(values, 6, sizeof(int), compare);
    for (n = 0; n < 6; n++)
        printf("%d ", values[n]);
    return 0;
}

然后我也尝试改变a本身的值:

#include <stdio.h>
#include <stdlib.h>

int values[] = {40, 10, 100, 90, 20, 25};

int compare (const void *a, const void*b)
{
    a=b;
    return ( *(int*)a - *(int*)b);
}

int main ()
{
    int n;
    qsort(values, 6, sizeof(int), compare);
    for (n = 0; n < 6; n++)
        printf("%d ", values[n]);
    return 0;
}

但是,我发现它们都有效.. 谁能向我解释为什么我需要在 compare 的参数列表中使用 const 如果它们仍然可以更改?

【问题讨论】:

  • 你把 const 扔掉了。改为转换为 const int*
  • 引用我自己的话:(im)mutability 是对象本身的固有属性,与用于访问它的指针的限定无关 - 因为values 不是t const-qualified,修改它是完全合法的......

标签: c memory pointers


【解决方案1】:

它仅在这种情况下有效,因为您正在处理的指针最初不是恒定的。抛弃常量然后修改一个值是未定义的行为。 UB的意思是app可以做任何事情,从成功到崩溃到让紫龙飞出你的鼻孔。

【讨论】:

  • 上一个UB故事里有紫龙... :(
  • 如果底层对象是const,则只有UB。
  • 技术上正确(最好的正确),但他仍在摒弃 constness,这充其量是一种代码气味,最坏的情况是世界末日的核导弹发射破坏日。跨度>
【解决方案2】:

它可以保护您避免愚蠢的错误,而不是在您努力犯错误时。
(int *)aaconst something * 是一种不好的做法,请改用(const int *)a
@987654325 @ 当aconst void * 时是可以的,因为只有指向的值是const。如果您希望同时禁止 *a = xa = x,请将 a 声明为 const void * const

【讨论】:

    【解决方案3】:

    案例 1:您正在使用静态强制转换来抛弃 constness。您违反了为该方法定义的合同。

    案例 2:您没有更改 a 的内容(即 const),而是分配包含 const void 指针的变量 a。

    对于实际意义:对于案例 1。)如果 a 没有真正指向变量,您可能会朝自己的脚开枪。

    建议:只有在你知道自己在做什么的情况下,才能抛弃 constness。

    【讨论】:

    • 在案例 1 中没有这样的契约,或者至少没有语言语义强制执行的契约(即编译器无法优化调用代码,假设 const-qualified 参数不会是修改 - 即使restrict 存在);这“只是”一个约定......
    • 合约不是给编译器的,而是给那个在 case 1 中调用函数并期望之后他的第一个参数不变的可怜人。
    【解决方案4】:

    其实。

    int compare (const void *a, const void*b);
    

    这里有两件事你需要考虑,指针和指针指向的内存位置。指针不是常量,但内存位置是。

    如果您将签名更改为:

    int compare (const void *const a, const void *const void);
    

    那么一切都会是常量。在您的情况下,您可以更改指针但不能更改值。这样你的指针就可以指向不同的内存位置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-20
      • 1970-01-01
      • 2016-05-25
      • 2017-03-25
      • 2019-12-06
      • 2015-08-14
      相关资源
      最近更新 更多