簡體   English   中英

在C ++中增加常量

[英]Incrementing a Constant in C++

有人可以向我解釋為什么這段代碼有效嗎? 我覺得編譯器不應該允許我做我做的事情(移動一個指針指向一個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

程序以兩種方式調用未定義的行為 ,這意味着程序的行為是不可預測的,即使看似正常的行為也是可能的。

首先,雖然我們可以將結構的各個元素視為數組,但是一旦遞增指針就不再有效取消引用它,它甚至不必指向它很可能指向填充的下一個元素。

其次,嘗試在未定義的行為中改變const。 C ++標准草案7.1.6.1cv-qualifiers4段說:

[...]任何在其生命周期內修改const對象的嘗試(3.8)都會導致未定義的行為。

我們可以看到,為了指針算法的目的,非數組變量被視為一個元素的數組,來自5.7添加運算符 ,它說:

出於這些運算符的目的,指向非陣列對象的指針與指向長度為1的數組的第一個元素的指針的行為相同,其中對象的類型為其元素類型。

此外,從同一部分中取消引用一個數組末尾的未定義行為:

當向指針添加或從指針中減去具有整數類型的表達式時,結果具有指針操作數的類型。 [...]如果指針操作數和結果都指向同一個數組對象的元素,或者指向數組對象的最后一個元素,則評估不應產生溢出; 否則,行為未定義。

我們可以從第5.3.1節的一元運算符中進一步看出:

一元*運算符執行間接:它所應用的表達式應該是指向對象類型的指針,或指向函數類型的指針,結果是引用對象或函數的左值

當我們取消引用我們期望的指針和我們不能保證的對象 ,一旦我們超過結束。

GNU C ++庫有一個更容易訪問的解釋說( 強調我的 ):

您只能取消引用指向數組的指針。 如果你的數組指針指向數組外部 - 甚至只是一個結束 - 並且你取消引用它, 就會發生糟糕的事情。

(這個答案對於Visual Studio 2010是正確的 - 不確定其他編譯器。)

以下是允許這樣做的原因:

const修飾符是編譯器的指令,用於防止用戶編輯聲明的變量。 使用該變量時,編譯器將阻止您對其進行更改,並要求您將const修飾符添加到與該特定變量關聯的指針。

但是,所有像其他變量值一樣,它駐留在內存中,並且編譯器不會專門阻止訪問或編輯該內存。 如果您選擇顛覆編譯器的指令,就像在代碼中一樣,可以像使用指針的任何其他內存地址一樣訪問和修改它。

如果您希望阻止程序訪問內存中的區域,可以參考Windows的以下內存保護常量:

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

結構中的數據項存儲在內存中的堆棧中,因此當您創建指針並使其指向第一項時,存儲的地址是堆棧指針的位置。當您遞增它時,堆棧指針遞增到堆棧上的下一個位置,即第二個數據項。 因此這可能是可能的原因。因為否則它應該給出錯誤,而且我們也不能像數組那樣對待結構。 Bt仍然可以指向下一個項目,只有當我們考慮在內存中創建的堆棧時才有可能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM