[英]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.