c++ - 在 C++ 中递增常量

标签 c++ pointers constants undefined-behavior

有人可以向我解释为什么这段代码有效吗?我觉得编译器不应该允许我做我所做的事情(移动一个 int 指针指向一个 const int),或者我至少会期待编译器警告或段错误。改变常量值的想法似乎是错误的。

代码:

#include <iostream>

using namespace std;

struct test_struct {
    int i;
    const int j;
};

int main() {
    cout << "Create a struct with int i = 100 and const int j = 101." << endl;
    test_struct test{100, 101};
    cout << test.i << endl;
    cout << test.j << endl;
    cout << "Create pointer p and point it to int i." << endl;
    int* p1 = &test.i;
    cout << *p1 << endl;
    cout << "Increment pointer p, which should now be pointing at const int j." << endl;
    p1++;
    cout << *p1 << endl;
    cout << "Dereference p and increment it." << endl;
    (*p1)++;
    cout << *p1 << endl;
    cout << test.j << endl;
}

输出:

Create a struct with int i = 100 and const int j = 101.
100
101
Create pointer p and point it to int i.
100
Increment pointer p, which should now be pointing at const int j.
101
Dereference p and increment it.
102
102

最佳答案

你的程序调用了undefined behavior有两种方式,这意味着您的程序的行为是不可预测的,即使看似正常的行为也是可能的。

首先,虽然我们可以将结构的各个元素视为数组,但一旦您递增指针,取消引用它就不再有效,它甚至不必指向它很可能指向的下一个元素填充。

其次,试图在同样未定义的行为中改变常量。 draft C++ standard 7.1.6.1 The cv-qualifiers4 说:

[...]any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.

我们可以看到,出于指针运算的目的,非数组变量被视为一个元素的数组,来自 5.7 Additive operators 部分,它说:

For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

此外,在同一节中取消对数组末尾的引用是未定义的行为:

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. [...] If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

我们可以从 5.3.1 一元运算符 部分进一步看出:

The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function

当我们取消引用我们期望的指针和对象时,我们不能保证一旦我们过了最后就拥有。

The GNU C++ Library有一个更容易理解的解释,上面写着(强调我的):

You can only dereference a pointer that points into an array. If your array pointer points outside the array -- even to just one past the end -- and you dereference it, Bad Things happen.

关于c++ - 在 C++ 中递增常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26128980/

相关文章:

c++ - union 体的活跃成员,统一的初始化和构造函数

c - 类型指针而不是变量名?

c++ - 如何删除二维double数组

c - GCC:为什么常量变量没有放在 .rodata 中

rust - 条件评估的替代方法是什么,例如 Rust const 函数中的 if 或 match?

C++ 函数中两个类之间的交互

c++ - 使用 C++ 在 Linux 中设置系统和硬件时间

c++ - 恒定的正确性和 <random>

c++ - 如何获得与Python中相同的系统时间?

c - printf 的正确用法是什么来显示用 0 填充的指针