【问题标题】:const and pointers in CC中的常量和指针
【发布时间】:2015-02-19 17:44:50
【问题描述】:

将 const 与指针一起使用可以使指针对象无法通过使用相关指针取消引用来修改。但是为什么我也不能修改指针不直接指向的东西呢?

例如:

int a = 3;
const int* ptr = &a;
*ptr = 5;

不会编译。但是为什么

*(ptr + 2) = 5;

也不编译?我不会更改指针指向的内容。
所以我们必须说,以这种方式将 const 与指针一起使用不仅使指针指向的内容不可修改(通过取消引用指针),而且还有什么,我们使用指针得到的地址是什么?

我知道在示例中我试图访问未分配的内存,但这只是为了讨论。

【问题讨论】:

  • 那么您是否期望编译器假定只有第一个 sizeof(int) 字节是 const?更有意义的是,编译器将假定使用ptr 访问的任何内存地址都是只读地址(“物理上”是只读的,或者至少在使用@987654326 的函数的“透视”中是只读的@)。

标签: c pointers constants


【解决方案1】:

ptr +2ptr 具有相同的类型,即指向const 对象的指针。

指针算法假设指向的对象是一个基本类型相同的数组。此类型包括const 限定条件。

【讨论】:

  • 所以就像 int + float = float,所以 const [type]* + some value = const [type]*,对吧?
  • @Root149,类似的东西,是的。将任何整数类型添加到指针类型都会返回相同的指针类型。
  • 只有在指针类型衰减的情况下(当涉及到指针时,所有东西都会被扁平化为指针,包括数组),其中普通整数类型会被提升为可以代表所有东西的类型。
【解决方案2】:

const 引入的不可修改性取决于 const 的写入位置。

如果你写

const int * ptr = &a;

(或int const * ptr = &a;),const指的是指针,所以禁止使用指针写入目标。

(OTOH,如果你写了

int * const ptr = &a;

你不能修改ptr。)

在你的情况下,所有涉及写入目的地的事情都是被禁止的。

这包括*ptrptr[0](它们是等效的),还包括所有涉及修改目标地址的内容,例如*(ptr + 2)ptr[2]

【讨论】:

  • (注意const int *int const * 是同一个东西——指向 const 的指针,而不是 const 指针。)
  • 还要注意,给定“int * const ptr = &a;”,您可以写“*ptr = 5;”,但不能写“++ptr”。 stackoverflow.com/questions/1143262/… 的答案中很好地涵盖了规则 - 答案的第一行 - “向后阅读” - 总结得很漂亮。
  • @frasnian 这基本上就是我说的——++ptr 被“你不能修改ptr”所覆盖。
【解决方案3】:

虽然其他答案解释了为什么它不起作用的技术细节,但我想提供一个更普遍的原因:这是唯一有意义的事情。

问题在于编译器没有通用的方法来判断p + something 是否与p 相同,因为something 可以任意复杂。像“pp + 0 指向的值是不可修改的,但其他值仍然可以修改”这样的规则不能在编译时检查:想象一下,如果你写:

*(p + very complex expression) = ...

您的编译器是否应该能够确定very complex expression 是否为零?怎么样

int s;
scanf("%d", &s);
*(p + s) = ...

这种情况下编译器应该怎么做?

这里唯一合理的选择是使通过p 访问的任何值都不可修改。

【讨论】:

  • 此行为不是由编译器决策中的任何歧义引起的。这是类型系统规则的一个简单而正确的结果。
  • @JamesT.Huggett:我不确定您所说的“编译器决策中的歧义”是什么意思;确实,这种行为是打字规则的结果,我的回答只是试图解释为什么类型系统的规则是这样设计的。
【解决方案4】:

由于指针也可以用作数组(想想argv),因此编译器会限制涉及指针的每次访问。这样整个数组都是只读的。

【讨论】:

  • 嗯,argv 只是一个指针,因为写 char* argv[] 等价于 char** argv。我们只是创造了一个数组的错觉。
  • @Root149 数组与否在访问它时没有区别,因为无论如何访问都是通过指针进行的。
  • @Root149:对。由于这种错觉,编译器不知道您的指针是否也是这样的“错觉”。它可以用作数组,如argv,因此必须限制对它的每次写入访问(无论是ptr[0] 还是ptr[100])。
【解决方案5】:

让我们考虑一下表达式的类型。

const int* ptr = &a;

ptr 的类型是const int*

所以*ptr 的类型是const int。不可修改。

(ptr + 2) 的类型仍然是 const int*,所以 *(ptr + 2) 的类型是 const int,这又是不可修改的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-23
    • 2021-10-02
    • 2013-01-04
    • 2022-07-06
    • 1970-01-01
    • 2012-09-14
    • 2023-04-07
    • 1970-01-01
    相关资源
    最近更新 更多