if
嵌套出現時,else
屬於離它最近的不完整的if
switch
的最後一個case
也加上break
是個好習慣,以避免在後面追加新的case
時忘記添加break
goto
通常不是好事,惟一的例外多是須要從多重循環中直接退出時比較方便,可是這也能夠經過把整個循環包裝成一個函數,而後在須要退出的時候直接return
來解決%
不能用於浮點數移位⚠️C只規定對於unsigned值使用邏輯移位,對於signed值使用的移位方式則由編譯器決定!數組
算數移位:ide
右移時只能一位一位移,符號位爲0則補0,爲1則補1,以保證與原值同號函數
⚠️C中的賦值符實際上會將左值做爲運算結果返回,因此下面這種連續賦值實際上是合法的:測試
int x = 3; int y = x = x + 2; // 合法
可是實際上不管x
是否爲int
,x + 2
都會返回一個int
結果並賦值給x
,而若x
實際上是一個char
,這樣的賦值就會致使結果的高位被截去,於是獲得的x
的值的完整性是沒法保障的,進而y
的值也不必定符合指望。lua
⚠️sizeof操做符判斷它的操做數的類型長度(sizeof不是函數!!),而並不須要知道它的操做數(也能夠是表達式)的實際值指針
// 括號 sizeof(x); sizeof x; // 二者徹底等價,以字節爲單位返回變量x的長度 // 數組 sizeof(arr); // 返回數組的字節數(不是數組長度!!) // 表達式 sizeof(a = b + 3); // 判斷長度不須要知道表達式的實際值,所以sizeof不會執行接收到的表達式,a也並不會被賦任何值 // 給sizeof一個有反作用的表達式將會獲得以下警告: // Expression with side effects has no effect in an unevaluated context
⚠️自增 & 自減code
++和--真是C永恆的話題。。
int a = 10; int b = a++; // 合法:a加一的結果先被做爲一個值拷貝後賦值給b,而後a被加一 int c = (++a)++; // 非法:++a實際是a值的拷貝,不是一個左值,所以不可自增自減
逗號操做符分隔多個表達式,表達式們從左到右逐個求值,一整條逗號表達式的值等於最後一個小表達式的值。內存
惟一的用處多是用來簡化同時出如今while循環前面和內部的語句(能夠用逗號鏈接起來放進while的條件裏,而後把原來的條件做爲最後一個表達式)。。由於while每一輪開始前都會執行一遍條件
⚠️隱式類型轉換ci
C中的整型算數運算至少都會以缺省整型類型的精度來進行,即使全部操做數都是更小的類型(居然是這樣!):get
char a, b, c; a = b + c; // 雖然a, b, c全都是較小的char,b和c也會先被提高爲int,而後執行加法獲得int結果,再將結果截短賦值給a
可是,若是直接參與運算的值已經達到了不用提高的標準而運算結果將會產生溢出,那麼即便左邊變量足夠接收完整的結果,獲得的也是先溢出再被加長的值:
int a, b; long c = a * b; // 就算a和b相乘產生溢出,右邊表達式的計算結果也只是溢出後的int,不會由於c夠大就提高a和b的長度
對於左右都有表達式的運算符,先計算左邊表達式仍是先計算右邊表達式是由編譯器決定的,所以以下表達式的結果實際沒法預測:
a = ++b + --b; // C只規定自增自減運算要優先加法運算執行,可是先求加法的左邊(++b)仍是右邊(--b)則由編譯器決定
有更好的例子以下:
f() + g() - h(); // 同級運算符從左到右執行的規則只約束例子中的加法比減法先執行,而不約束執行加法時必定要先算f()再算g()
甚至編譯器也能夠先把每個小的表達式求出來再作運算:
f() + f() * f(); // 先無視運算優先級,直接求出3個f()再進行總體運算也是能夠的,此時3次f()的調用順序徹底取決於編譯器實現
⚠️標準容許將指向數組元素的指針和指向該數組最後一個元素後面那個位置的指針相比較,但不容許將它和指向數組第一個元素以前的內存位置的指針相比較
這是什麼神仙規定。。不過大部分狀況下查得不嚴,仍是能夠比較的,只是移植性會稍微降低
可變參數列表
stdarg.h
va_list
va_start
、va_arg
、 va_end
#include <stdarg.h> int sum(int argNum, ...) { // 對未知個數的參數求和 va_list args; va_start(args, argNum); // 使用va_start(可變參數列表 + 最後一個命名參數)將args指向可變參數列表的第一個元素 int result = 0; for (int i = 0; i < argNum; i ++) { result += va_arg[args, int]; // 使用va_arg得到可變參數列表中的下一個參數併爲它指定類型 } va_end(args); // 使用va_end結束訪問可變參數列表 return 0; }