简体   繁体   English

在C ++中增加常量

[英]Incrementing a Constant in C++

Can someone explain to me as why this code works? 有人可以向我解释为什么这段代码有效吗? I feel like the compiler should not allow me to do what I have done (move an int pointer to point at a const int), or alternatively I would at least expect a compiler warning or a segfault. 我觉得编译器不应该允许我做我做的事情(移动一个指针指向一个const int),或者我至少会期望编译器警告或段错误。 The idea of changing the value of a constant just seems so wrong. 改变常数值的想法似乎是错误的。

Code: 码:

#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;
}

Output: 输出:

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

You program invokes undefined behavior in two ways, which means the behavior of your program is unpredictable, even seemingly normal behavior is possible. 程序以两种方式调用未定义的行为 ,这意味着程序的行为是不可预测的,即使看似正常的行为也是可能的。

First although we can treat the individual elements of a struct as arrays once you increment the pointer it is no longer valid to dereference it, it does not not even have to be pointing to the next element it could very well be pointing to padding. 首先,虽然我们可以将结构的各个元素视为数组,但是一旦递增指针就不再有效取消引用它,它甚至不必指向它很可能指向填充的下一个元素。

Second, attempting to alter a const in also undefined behavior. 其次,尝试在未定义的行为中改变const。 The draft C++ standard section 7.1.6.1 The cv-qualifiers paragraph 4 which says: C ++标准草案7.1.6.1cv-qualifiers4段说:

[...]any attempt to modify a const object during its lifetime (3.8) results in undefined behavior. [...]任何在其生命周期内修改const对象的尝试(3.8)都会导致未定义的行为。

We can see for the purposes of pointer arithmetic a non-array variable is treated as an array of one element, from section 5.7 Additive operators which says: 我们可以看到,为了指针算法的目的,非数组变量被视为一个元素的数组,来自5.7添加运算符 ,它说:

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. 出于这些运算符的目的,指向非阵列对象的指针与指向长度为1的数组的第一个元素的指针的行为相同,其中对象的类型为其元素类型。

and furthermore dereferecing one past the end of an array is undefined behavior, from the same section: 此外,从同一部分中取消引用一个数组末尾的未定义行为:

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. 否则,行为未定义。

we can further see from section 5.3.1 Unary operators which says: 我们可以从第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 一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是引用对象或函数的左值

when we dereference a pointer we expect and object which we are not guaranteed to have once we are one past the end. 当我们取消引用我们期望的指针和我们不能保证的对象 ,一旦我们超过结束。

The The GNU C++ Library has an easier to access explanation which says ( emphasis mine ): GNU C ++库有一个更容易访问的解释说( 强调我的 ):

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. 如果你的数组指针指向数组外部 - 甚至只是一个结束 - 并且你取消引用它, 就会发生糟糕的事情。

(This answer is correct for Visual Studio 2010 - not sure about other compilers.) (这个答案对于Visual Studio 2010是正确的 - 不确定其他编译器。)

Here is the reason why this is allowed: 以下是允许这样做的原因:

The const modifier is an instruction to the compiler to prevent the user from editing that declared variable. const修饰符是编译器的指令,用于防止用户编辑声明的变量。 When working with that variable the compiler will prevent you from making changes to it, and require you to add the const modifier to pointers associated with that particular variable. 使用该变量时,编译器将阻止您对其进行更改,并要求您将const修饰符添加到与该特定变量关联的指针。

However, all like other variable values, it resides in memory, and the compiler doesn't specifically prevent access to or editing of that memory. 但是,所有像其他变量值一样,它驻留在内存中,并且编译器不会专门阻止访问或编辑该内存。 It can be accessed and modified just like any other memory address using a pointer, if you choose to subvert the compiler's instructions, as you have done in your code. 如果您选择颠覆编译器的指令,就像在代码中一样,可以像使用指针的任何其他内存地址一样访问和修改它。

If you are looking to prevent program access to areas in memory, you can refer to the following memory protection constants for Windows: 如果您希望阻止程序访问内存中的区域,可以参考Windows的以下内存保护常量:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx

the data items in the structure are stored on stack in memory,so when you create a pointer and make it point to the first item,the address that is stored is the position of the stack pointer.when u increment it the stack pointer increments to the next location on stack ie the second data item. 结构中的数据项存储在内存中的堆栈中,因此当您创建指针并使其指向第一项时,存储的地址是堆栈指针的位置。当您递增它时,堆栈指针递增到堆栈上的下一个位置,即第二个数据项。 thus this might be the possible reason.because otherwise it should have given an error,and also we can't treat a structure like an array. 因此这可能是可能的原因。因为否则它应该给出错误,而且我们也不能像数组那样对待结构。 Bt still its able to point to the next item,possible only if we consider the stack created in memory. Bt仍然可以指向下一个项目,只有当我们考虑在内存中创建的堆栈时才有可能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM