1.define宏定义

define中的#和##:
(1)#可以将define中的参数转化为字符串,例如:
#define PRINT(x) printf(#x “ is %d”, x);
(2)##可以将define中的参数转化为某个标识符的一部分,例如:
int tmp_a = 23;
#define PRINT(x) printf(#x “ is %d”, tmp_##x);

define的位置:
宏定义可以出现在所有函数外部或者某函数内部,遵循两个规则:
第一, 内部定义覆盖外部定义。如果全局的宏定义与某内部宏定义重名时,VC6.0编译器会提示warning但不出错,且以内部宏定义为准。
第二, 定义点后均可使用,不以函数内外划分作用域,仅以文本中出现位置前后划分。

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,所有的参数都要括起来,以防止macros(a+b)的情况出现;而且要注意是否有类似macros(i++)的情况出现,防止在文本替换后i++执行多次。
第二, 宏不做类型检查,而且预处理展开后消失于无形,编译出错了很难找到错误。
第三, 使用宏后该“函数”不能取址,不能作为函数指针传递给另一个函数。
第四, 一般使用inline函数代替宏函数,类似的,一般使用const变量代替宏变量。

2.strncpy和strncat

strncpy(dest, src, size);
使用strncpy(a, b, size)函数时,根据size值分两种情况:
第一,size比字符串b长度大时,将b字符串赋给a,再将a中size-b.length的多余位置赋值为\0。
第二,size比字符串b长度小时,将size长度的b子字符串赋给a,但不自动在后面添加\0。

strncat(dest, src, size);
使用strncat(a, b, size)函数时,根据size值分两种情况:
第一,size比字符串b长度大时,将b字符串赋给a第一个\0结束符处,并自动在右面添加\0,多余的size-b.length位置不赋值。
第二,size比字符串b长度小时,将size长度的字符串赋给a第一个\0结束符处,并且自动在后面添加\0。

3.printf和scanf

printf(“%x, %x, %x”, a, b, c);
printf注意事项:
第一, pirntf参数从右向左依次压栈。
第二, 字符串%×和后面参数从左至右依次映射,当参数多出时可忽略不计。
第三, 字符串%×和后面参数从左至右依次映射,当%×多出时,打印出来的结果不可预测(因为VC下参数从右向左压栈,所以多出的%×只能对应不可预知的内存)。

其他

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

5.对于数组char a[100],sizeof(a)的值是100,表示数组大小,而sizeof(&a)按道理来说应该是4,表示指向数组a的指针的大小,但是某些MSVC版本对arrayName和&arrayName是不区分的,需要安装sp1的MSVC的补丁才可去掉这个bug。

6.C语言中,不写返回类型的函数,一般默认为int型,而C++中必须指明返回类型。但在一般的编译器实现中,可能会做放宽处理,例如VC6.0中可以接受C++函数没有返回类型,默认为int。

7.返回值为数组指针
如果函数返回值是int(*)[NUM]类型,不可写成int(*)[NUM] func() {}的形式,而应该写成:
int (*func)() [NUM] {}
或者使用typedef来简化:
typedef int(*)[NUM] type;
type func() {}

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

8.结构体
结构体有赋值操作,但是没有比较操作,可以重载==等这些比较运算符;同时,最好别用memcmp函数进行结构体的比较操作,因为要考虑到结构体的对齐问题,且填充的字节是随机的。

9.函数指针
void func() {}
printf(“%p  %p  %p”, func, &func, *func);
其结果是一样的,原因在于:
函数名就是函数名,除了少量情况,它会退化为函数指针,即发生function-to-pointer转换。fun单独放着的时候就会发生退化,而在&fun的情况下不会退化,所以单独的fun和&fun的类型、值都一样。而*fun则是fun先发生退化,变成函数指针,*变成函数类型,然后再退化成函数指针,所以函数类型怎么*都一样。(maybe)

10.(int&)a和(int)a的区别
(int&)a不经过转换,直接得到a在内存单元的值;(int)a则是a在内存中的值转换成int类型,那么存在两种情况:
第一, a类型是int,此时(int&)a和(int)a是相等的。
第二, a类型是float等,由于float在内存中存储的形式是符号位+指数+尾数,而阶码采用增码,为数采用源码,与int的存储形式不同。(int)a会先将内存中的值转换成int类型,然后给a,而(int&)a则直接将内存中的值给a,不经过转换,所以此时两者不相等。