寫在前面的話:
原文鏈接爲:https://blog.csdn.net/qq_29169813/article/details/51416281。感謝博主,是真的結合自己的感受寫出來的,而且練習題哈哈哈和我遇上的也是一樣的。我申請過啦,博主同意我轉載的哦~
1.什麼是未定義行爲
簡單地說,未定義行爲是指C語言標準未做規定的行爲。編譯器可能不會報錯,但是這些行爲編譯器會自行處理,所以不同的編譯器會出現不同的結果,什麼都有可能發生,這是一個極大的隱患,所以我們應該儘量避免這種情況的發生。
1.1特徵
首先定義不確定副作用行爲:
粗略而言:是指在同一個表達式中同一對象修改一次以上的行爲。
諸如:同一變量被修改以後又進行了引用的自增, 自減和賦值。未定義行爲是指:包含多個不確定的副作用的代碼的行爲
在網上了解了一番,發現未定義行爲有很多,而我初出茅廬,遇到的情況不多,只有借鑑前人的經驗。總結了一些前人遇到的問題。下面三種未定義行爲是前人總結的,我只是加上了一點自己的理解。有錯誤望指出。
附原文地址:http://www.itoldme.net/archives/904
1.1.1第一例(同一個表達式中有多種運算符)
在同一個表達式中多種運算符一起計算的時候,即使我們知道各符號都有自己的優先級或者是人爲的加上括號限制計算順序,但是我們卻不知道編譯器會先計算哪一段,計算順序完全取決於編譯器,所以結果並不一定按照我們預想中的輸出。
代碼段一:
int i=7;
printf(“%d”, i++*i++);
編譯器可能選擇變量的舊值相乘以後再對二者進行自增運算,但是無法確保自增或自減一定會在1.輸出變量原值之後
,2.對表達式的其它部分計算之前
立即進行。
代碼段二
int a=5,b;
b=++a*–a;
b的值不能確定
代碼段三
int i = 5;
int j = (++i) + (++i) + (++i);
的值不能確定
代碼段四
#include <stdio.h>
int main(){
int i = 0;
int a[] = {10,20,30};
int r = 1 * a[i++] + 2 * a[i++] + 3 * a[i++];
printf("%d\n", r);
return 0;
}
這段代碼也並不是我們想象中的那樣按照優先級來計算,編譯器選擇了他自己的一種套路,
此段代碼詳細實現情況請戳鏈接:http://blog.jobbole.com/53211/
1.1.2 第二例(同一語句中各參數的求值順序)
在同一語句中,有多個表達式,我們不能確定編譯器先調用哪一個表達式進行運算,運算之後又會對另一個表達式產生影響,因爲他不一定是按照我們想象中自左向右進行調用的。
代碼段一
printf("%d,%d\n",++n,power(2,n));
代碼段二
int f(int a, int b);
int i = 5;
f(++i, ++i);
1.1.3第三例(通過指針修改const常量的值)
編譯器對於向常量所在內存賦值這件事的處理是未定義的。即在對常量的內存操作也許並不是我們想象的那樣。
代碼段一
int main()
{
const int a = 1;
int *b = (int*)&a;
*b = 21;
printf("%d, %d", a, *b);
return 0;
}
該段代碼的詳細實現請戳鏈接:http://www.cnblogs.com/wghost/p/3280074.html
練習題
解析:根據上面的總結,A選項,我的理解是我們不知道編譯器會怎麼選擇自增和賦值的順序,所以這是由編譯器決定的,屬於未定義行爲。B選項,”hello“這個字符串屬於一個字符串常量了,指針p指向了這個字符串常量,下一語句通過這個指針來直接修改常量第二個字符,這也屬於未定義行爲。選項C,只是通過指針找到第二個字符並將它賦值給一個字符變量,並沒有改變這個字符串常量,所以不屬於未定義行爲。選項D,在printf語句中,i++和i–誰先執行由編譯器決定,這是未定義行爲。故此題選C。