[英]GCC: dereferencing ‘void *’ pointer while taking address
我注意到GCC觸發器:
warning: dereferencing ‘void *’ pointer
在采用已取消引用的void
表達式的地址時,例如:
int main()
{
void *p = "abcdefgh";
printf("%p\n", p);
printf("%p\n", &*p);
return 0;
}
但是,根據C標准,表達式p
等於&*p
:
§6.5.3.2地址和間接運算符
一元&運算符返回其操作數的地址。 如果操作數的類型為“類型”,則結果的類型為“類型的指針”。 如果操作數是一元*運算符的結果,則不會對該運算符和&運算符求值,並且結果都好像都被省略了,除了運算符上的約束仍然適用並且結果不是左值。
同樣重要的是要知道Clang不會觸發此警告。
免責聲明
為了獲得更好的解釋,請考慮以下事項:
int main()
{
int *p = NULL;
printf("%p\n", (void *) p);
printf("%p\n", (void *) &*p);
return 0;
}
該代碼可與Clang和GCC一起編譯並完美運行。 C標准對void
指針很清楚,您可以取消引用它們(從而獲得一個void
值),但不能使用表達式的結果。
我假設這里的問題是“為什么?/有什么用?”。 在這種情況下,這實際上是一些標准的措辭/針對編譯器開發人員的靈活性。
嚴格來說*(void*)
總是不好的,編譯器可以警告您。 在實踐中,正如您正確指出的那樣,在評估指針所指向的內容時,指針實際上從未真正被取消引用,因此,天真的編譯器實現將以這種方式查看並毫無問題地進行掩飾這並說“指針:它們是數字對嗎?這是0xFFF ....”。
實際上,有時並非如此。 有時候編譯器變得很聰明。 沒有想到好的例子,但這不是重點。
關於“從未被評估”,我認為可能需要注意以下幾點:
賦予編譯器自由執行其所需功能的原因,部分原因是為了簡化編譯過程本身,而不僅僅是輸出更好的實現。 您指向的下一個編譯器可能會拒絕。 只是因為它更容易,而且沒有必要。
其次,這並不是警告的重點。 如果我在代碼審查中看到了這一點:
int i = 3;
if (3-i) {
((int*)(NULL)) += 4;
}
我的反應不會是:“哦,還好,沒有評估。” 但是“哇!”。 這也是編譯器所做的。 它告訴您它認為您可能已經做了一些可能需要重新考慮的事情,在這種情況下,將const char *
稱為void *
。 我同意gcc。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.