簡體   English   中英

在C中更改const值

[英]changing const value in C

我在以下代碼段中發現了這一點

const int i = 2;  
const int* ptr1= &i;  
int* ptr2 = (int*)ptr1;  
*ptr2 =3;

i的值更改為3。我想知道為什么允許這樣做。 這在什么情況下可能會有所幫助?

之所以允許,是因為您已將ptr1的常量轉換為非const指針,從而破壞了它的常量。 這就是為什么強制轉換可能非常危險的原因。

請注意,某些編譯器(例如GCC)將不允許您放棄這種const狀態。

您通過玩指針技巧破壞了穩定性保證。 不能保證該方法始終有效,並且可能會根據您所處的系統/ OS /編譯器調用幾乎任何行為。

不要那樣做

或至少不要這樣做,除非您真的知道自己在做什么,甚至知道它不是最不便攜的。

“允許”與“預防”相對,但也與“禁止”相對。 您已經看到,沒有禁止修改const對象,但這並不意味着它是允許的。

從“允許”的意義上說,不允許“修改” const對象。 該程序的行為不是由標准定義的(請參見6.7.3 / 5)。 碰巧的是,在您的實施中,在該運行中,您看到了值3。在另一個實施中或在另一天,您可能會看到不同的結果。

但是,這並不是“防止”的,因為使用C強制轉換的方式,在編譯時檢測它是一個暫停的問題。 在運行時檢測到它需要對所有內存訪問進行額外檢查。 該標准旨在不給實現帶來很多開銷。

完全支持拋棄const的原因是,如果您有指向非const對象的const指針,則該語言允許(從兩種意義上)修改該對象。 為此,您需要擺脫const限定符。 這樣的結果是程序員也可以從指向實際上是const的對象的指針中丟棄const限定符。

這是一個(有點愚蠢的)代碼示例,出於這個原因,該示例放棄了const限定符:

typedef struct {
    const char *stringdata;
    int refcount;
} atom;

// returns const, because clients aren't allowed to directly modify atoms,
// just read them
const atom *getAtom(const char *s) {
    atom *a = lookup_in_global_collection_of_atoms(s);
    if (a == 0) {
        // error-handling omitted
        atom *a = malloc(sizeof(atom));
        a->stringdata = strdup(s);
        a->refcount = 1;
        insert_in_global_collection_of_atoms(a);
    } else {
        a->refcount++;
    }
    return a;
}

// takes const, because that's what the client has
void derefAtom(const atom *a) {
    atom *tmp = (atom*)a;
    --(tmp->refcount);
    if (tmp->refcount == 0) {
        remove_from_global_collection_of_atoms(a);
        free(atom->stringdata);
        free(atom);
    }
}
void refAtom(const atom *a) {
    ++(((atom*) a)->refcount);
}

這是愚蠢的,因為更好的設計是向前聲明atom ,使指向它的指針完全不透明,並提供訪問stringdata的功能。 但是C不需要封裝所有內容,它允許您返回指向完全定義的類型的指針,並且它希望支持這種const用法,以呈現“確實”可修改的對象的只讀視圖。

const真正含義是“只讀”。

正如您所發現的, const對象的值可以更改,但是您必須使用彎曲的方法來實現。 在使用這些these回方法時,您將調用Undefined Behavior

它的工作原理,因為你已經明確地投了const指針對象的岬之遙。 雖然ptr1是指向const int的指針,而ptr2是指向int的指針,所以它的指針是可變的。

這樣做的理由很少,但是您可以找到一種避免代碼重復的情況。 例如:

const char* letter_at(char* input, int position)
{
    ... stuff ...
    return &found_char;
}

char* editable_letter_at(char* input, int position)
{
    return (char*)(letter_at(input, position));
}

(示例與“有效C ++ 3rd”的第3項中的C ++示例有些沖突)

如果要在C ++程序中放棄constness,請使用更C ++的樣式轉換:

int *ptr2 = const_cast<int*>(ptr1);

如果確實遇到了與這種類型的轉換相關的問題(您將始終如此),則可以通過搜索“ const_cast”來快速找到發生的位置,而不是嘗試在陽​​光下進行任何組合。 此外,它還會幫助可能會或可能不會來追隨您的其他人。

在少數情況下,我可以看到這很有幫助。 他們中的大多數是極端情況。 如果您使用C ++開發,我將不惜一切代價避免這種情況。

C強制類型轉換告訴編譯器您知道自己在做什么,並且可以確保最終一切正常。 如果您在使用它們時未完全了解自己在做什么,則可能會遇到麻煩。

在這種情況下,編譯器完全有權限將i放入只讀內存,因此該代碼在運行時將崩潰。 或者,它可能如您所見。 標准將其指定為未定義的行為,因此實際上可能發生任何事情。

C最初被設計為使用Unix編寫,並故意賦予程序員處理數據的很大自由度,因為在OS編寫中,編寫高度實現特定於代碼的代碼通常會非常有用,該代碼執行在任何其他情況下都不安全的事情。 在常規應用程序代碼中,應謹慎進行強制轉換。

並且不要在C ++中使用C樣式的強制轉換。 C ++擁有自己的強制類型轉換系列,可以輕松地在代碼中進行搜索,並且通常會指定更多強制類型實際上在做什么。 在這種情況下,您將使用const_cast ,它可以准確顯示您在做什么,並且很容易找到。

因為C知道程序員總是知道自己在做什么,並且總是做正確的事情。 您甚至可以像這樣進行投射:

void* ptr2 = (int(*)(void(*)(char*), int[])) ptr1;
(*(int*)ptr2) = 3;

而且它甚至不會抱怨。

語句const int i = 2; 表示符號/變量i值為2 ,並且無法使用i更改該值; 但不能保證該值不能通過其他方式更改 (例如在OP的示例中)。

暫無
暫無

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

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