[英]gcc and clang are giving different results
#include <stdio.h>
int main(int argc, char *argv[]){
int a;
int *b = &a;
a = 10;
printf("%d %d\n", a, *b);
int p = 20;
int *q;
*q = p;
printf("%d %d\n", p, *q);
int *t = NULL;
return 0;
}
使用 gcc 編譯的上述程序在執行時會出現分段錯誤。 但是當用 clang 編譯時,它執行時不會出現分段錯誤。 任何人都可以給出原因嗎? gcc 版本是 9.3.0,clang 版本是 10.0.0。 操作系統是 ubuntu 20.04
問題不是源於編譯器,而是在代碼本身,特別是*q = p
,當您取消引用指針時,即使用*
,您正在訪問存儲在指針中的值,該值是它指向的地址,在在這種情況下,代碼無效,因為沒有分配給q
內存,它不指向任何地方(至少我們不希望它指向任何地方)。 你不能在它指向的內存中存儲任何東西,因為它不存在或者是由一些可能存儲在q
垃圾值給出的隨機內存位置。
鑒於上述情況,並且知道存儲在q
中的值可以是任何值,您可以並且應該在不同的編譯器、同一編譯器的不同版本,甚至同一台機器上的同一編譯器中但在同一編譯器的不同執行中預期不同的結果。程序,在某些時候它甚至可能以萬分之一的機會指向您想要的位置,然后程序會給您預期的結果,因此您的程序的行為是 undefined 。
如前所述, q
需要指向某個有效的內存位置,然后才能在該內存位置存儲值。 您可以通過分配內存並將其分配給q
或使q
指向現有的有效內存地址來實現,例如:
int p;
int *q;
q = &p; // now q points to p, i.e. its value is the address of p
現在你可以這樣做:
*q = 10; // stores 10 in the memory address pointed by(stored in) q, the address of p
// p is now 10
或者
int value = 20;
*q = value; // stores a copy of value in the address of the variable pointed by q, again p
// p is now 20
請注意,如果您使用額外的警告標志,例如-Wall
或-Wextra
等,編譯器可能會警告您有關錯誤構造的信息,例如您擁有的構造。
我不是編譯器方面的專家,但您肯定會在這里觸發一些未定義的行為:
int *q;
*q=p;
printf("%d %d\n",p,*q);
您在初始化之前取消引用指針q
。 這種段錯誤(或者更確切地說,不是段錯誤)的原因可能很少。 q
可以指向任何內存位置,例如,它可以在 Clang 的情況下從堆棧中彈出后保存b
舊值,從而寫入不受限制的內存。
不過,不確定您對這段代碼的初衷是什么。
任何人都可以給出原因嗎?
原因來自於 C 語言本身以及編譯器是如何構建的。
首先,C 語言 - 您的代碼調用未定義的行為。 首先,因為使用未初始化的變量是未定義的行為,但顯然是因為您在“無效”指針上應用*
運算符。 最重要的是,存在未定義的行為。
現在,因為存在未定義的行為,編譯器可以做他們想做的事情並生成他們想要的代碼。 簡而言之——沒有要求。
因此,編譯器編寫者並不關心編譯器在未定義行為情況下會做什么。 在編譯此特定代碼時,兩個編譯器的構造不同,在此特定情況下的行為也不同。 這不是故意的 - 沒有人關心,所以一些無關領域的隨機無關決定導致了兩個編譯器的這種行為。
兩個編譯器的行為不同的具體原因將來自檢查兩個編譯器的源代碼。 在這種情況下,檢查llvm及其文檔和gcc與gcc 開發人員選項將在此過程中有所幫助。
行*q=p;
使用未初始化的q
值; 訪問未初始化的變量是未定義的行為,允許編譯器以任何方式解釋該行代碼以及該行之前或之后的任何內容。
對於不同的優化級別,它也可能會給出不同的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.