1.define宏定義

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

define的位置:
宏定義可以出現(xiàn)在所有函數(shù)外部或者某函數(shù)內(nèi)部,遵循兩個(gè)規(guī)則:
第一, 內(nèi)部定義覆蓋外部定義。如果全局的宏定義與某內(nèi)部宏定義重名時(shí),VC6.0編譯器會(huì)提示warning但不出錯(cuò),且以內(nèi)部宏定義為準(zhǔn)。
第二, 定義點(diǎ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)
分析:解析一個(gè)串從左至右,一遍之后再?gòu)念^開(kāi)始。所以h(f(1,2)) -> g(f(1,2)) -> g(12) -> 12,而g(f(1,2)) -> #(f(1,2)) -> f(1,2)。

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

2.strncpy和strncat

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

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

3.printf和scanf

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

其他

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

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

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

7.返回值為數(shù)組指針
如果函數(shù)返回值是int(*)[NUM]類型,不可寫成int(*)[NUM] func() {}的形式,而應(yīng)該寫成:
int (*func)() [NUM] {}
或者使用typedef來(lái)簡(jiǎn)化:
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)體有賦值操作,但是沒(méi)有比較操作,可以重載==等這些比較運(yùn)算符;同時(shí),最好別用memcmp函數(shù)進(jìn)行結(jié)構(gòu)體的比較操作,因?yàn)橐紤]到結(jié)構(gòu)體的對(duì)齊問(wèn)題,且填充的字節(jié)是隨機(jī)的。

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

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