1.define宏定義

define中的#和##:
(1)#可以將define中的參數(shù)轉(zhuǎn)化為字符串,例如:
#define PRINT(x) printf(#x “ is %d”, x);
(2)##可以將define中的參數(shù)轉(zhuǎn)化為某個標(biāo)識符的一部分,例如:
int tmp_a = 23;
#define PRINT(x) printf(#x “ is %d”, tmp_##x);

define的位置:
宏定義可以出現(xiàn)在所有函數(shù)外部或者某函數(shù)內(nèi)部,遵循兩個規(guī)則:
第一, 內(nèi)部定義覆蓋外部定義。如果全局的宏定義與某內(nèi)部宏定義重名時,VC6.0編譯器會提示warning但不出錯,且以內(nèi)部宏定義為準(zhǔn)。
第二, 定義點后均可使用,不以函數(shù)內(nèi)外劃分作用域,僅以文本中出現(xiàn)位置前后劃分。

define解析順序:
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
void macrotest(void)
{
printf("%s,",h(f(1,2)));
printf("%s\n",g(f(1,2)));
}
最后答案是:12, f(1,2)
分析:解析一個串從左至右,一遍之后再從頭開始。所以h(f(1,2)) -> g(f(1,2)) -> g(12) -> 12,而g(f(1,2)) -> #(f(1,2)) -> f(1,2)。

define的缺陷:
第一, 對于所有的function-like macros,所有的參數(shù)都要括起來,以防止macros(a+b)的情況出現(xiàn);而且要注意是否有類似macros(i++)的情況出現(xiàn),防止在文本替換后i++執(zhí)行多次。
第二, 宏不做類型檢查,而且預(yù)處理展開后消失于無形,編譯出錯了很難找到錯誤。
第三, 使用宏后該“函數(shù)”不能取址,不能作為函數(shù)指針傳遞給另一個函數(shù)。
第四, 一般使用inline函數(shù)代替宏函數(shù),類似的,一般使用const變量代替宏變量。

2.strncpy和strncat

strncpy(dest, src, size);
使用strncpy(a, b, size)函數(shù)時,根據(jù)size值分兩種情況:
第一,size比字符串b長度大時,將b字符串賦給a,再將a中size-b.length的多余位置賦值為\0。
第二,size比字符串b長度小時,將size長度的b子字符串賦給a,但不自動在后面添加\0。

strncat(dest, src, size);
使用strncat(a, b, size)函數(shù)時,根據(jù)size值分兩種情況:
第一,size比字符串b長度大時,將b字符串賦給a第一個\0結(jié)束符處,并自動在右面添加\0,多余的size-b.length位置不賦值。
第二,size比字符串b長度小時,將size長度的字符串賦給a第一個\0結(jié)束符處,并且自動在后面添加\0。

3.printf和scanf

printf(“%x, %x, %x”, a, b, c);
printf注意事項:
第一, pirntf參數(shù)從右向左依次壓棧。
第二, 字符串%×和后面參數(shù)從左至右依次映射,當(dāng)參數(shù)多出時可忽略不計。
第三, 字符串%×和后面參數(shù)從左至右依次映射,當(dāng)%×多出時,打印出來的結(jié)果不可預(yù)測(因為VC下參數(shù)從右向左壓棧,所以多出的%×只能對應(yīng)不可預(yù)知的內(nèi)存)。

其他

4.rand()函數(shù)的最大取值是0X7fff,也就是2的15次方-1。

5.對于數(shù)組char a[100],sizeof(a)的值是100,表示數(shù)組大小,而sizeof(&a)按道理來說應(yīng)該是4,表示指向數(shù)組a的指針的大小,但是某些MSVC版本對arrayName和&arrayName是不區(qū)分的,需要安裝sp1的MSVC的補丁才可去掉這個bug。

6.C語言中,不寫返回類型的函數(shù),一般默認(rèn)為int型,而C++中必須指明返回類型。但在一般的編譯器實現(xiàn)中,可能會做放寬處理,例如VC6.0中可以接受C++函數(shù)沒有返回類型,默認(rèn)為int。

7.返回值為數(shù)組指針
如果函數(shù)返回值是int(*)[NUM]類型,不可寫成int(*)[NUM] func() {}的形式,而應(yīng)該寫成:
int (*func)() [NUM] {}
或者使用typedef來簡化:
typedef int(*)[NUM] type;
type func() {}

那么,如何保存函數(shù)的返回值呢,具體如下:
int a[num1][NUM];
int (*b)[NUM] = &a[num2];
b = func();

8.結(jié)構(gòu)體
結(jié)構(gòu)體有賦值操作,但是沒有比較操作,可以重載==等這些比較運算符;同時,最好別用memcmp函數(shù)進行結(jié)構(gòu)體的比較操作,因為要考慮到結(jié)構(gòu)體的對齊問題,且填充的字節(jié)是隨機的。

9.函數(shù)指針
void func() {}
printf(“%p  %p  %p”, func, &func, *func);
其結(jié)果是一樣的,原因在于:
函數(shù)名就是函數(shù)名,除了少量情況,它會退化為函數(shù)指針,即發(fā)生function-to-pointer轉(zhuǎn)換。fun單獨放著的時候就會發(fā)生退化,而在&fun的情況下不會退化,所以單獨的fun和&fun的類型、值都一樣。而*fun則是fun先發(fā)生退化,變成函數(shù)指針,*變成函數(shù)類型,然后再退化成函數(shù)指針,所以函數(shù)類型怎么*都一樣。(maybe)

10.(int&)a和(int)a的區(qū)別
(int&)a不經(jīng)過轉(zhuǎn)換,直接得到a在內(nèi)存單元的值;(int)a則是a在內(nèi)存中的值轉(zhuǎn)換成int類型,那么存在兩種情況:
第一, a類型是int,此時(int&)a和(int)a是相等的。
第二, a類型是float等,由于float在內(nèi)存中存儲的形式是符號位+指數(shù)+尾數(shù),而階碼采用增碼,為數(shù)采用源碼,與int的存儲形式不同。(int)a會先將內(nèi)存中的值轉(zhuǎn)換成int類型,然后給a,而(int&)a則直接將內(nèi)存中的值給a,不經(jīng)過轉(zhuǎn)換,所以此時兩者不相等。