简体   繁体   中英

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. 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. The draft C++ standard section 7.1.6.1 The cv-qualifiers paragraph 4 which says:

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

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:

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.

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:

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 ):

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.)

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. 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.

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:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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