1. #的作用
#是将其后的变量直接转换为字符串 void WriteLog(arg) {
printf(\}
2. ##的作用
##的作用是连接两个变量 如
#define combine_converse_str(x,y) x##y
int Err; int Num;
printf(\结果为:ErrNum
再如: int a=1; int b=2; int ab=3;
printf(\
结果为: 3
后面那句相当于printf(\
3. do{ }while(0)作用
1,空的宏定义避免warning: #define foo() do{}while(0)
2,存在一个独立的block,可以用来进行变量定义,进行比较复杂的实现。
3,用在宏定义上并且当宏定义需要定义成多条语句的组合时,可以保证这几条语句是一个整体的,并且可以消除使用这个宏定义后添加\所带来的报错,例如: #define aaa(x,y) \\ do{ \\
int a=0; \\ int b=0; \\ 函数1(x); \\ 函数2(y); \\ }while(0)
调用aaa(x,y); 时不会报错并且如果使用: if (m)
aaa(1,2); else
aaa(3,4);
时运行也不会使某些语句没有被运行到。
4. 数组名的使用
A. 数组名作为函数参数:数组名用在某个函数A的参数中时,处于函数传递效率原因,会
被强制转换成了指针,此后在函数A内就完全是一个值等于对应数组首地址的指针变量,可自加自减等 注意!只有在作为函数参数的情况下才会将数组名强制转换成指针,其他的都不会转换。 另:数组名作为函数参数传递时,函数声明的写法有多种 int aaa(char x[])
int aaa(char x[1]) int aaa(char x[100]) int aaa(char *x)
作为函数参数时的参数声明也和普通的数组定义一样要合法,比如不能 int aaa(char x[0]),因为定义一个数组也不能用 char x[0]来定义,编译器在检查参数的声明合法后,如果发现参数是数组,就会强制转换成指针,所以int aaa(char x[1])和int aaa(char x[100])的结果是一样的。
B. 数组名用在sizeof上:结果返回的是整个数组所占空间的大小,而不是一个指针的长度 C. 数组名与&和*:a与&a与&a[0]的值都相等,a是数组名,&a是整个数组地址,&a[0]
是数组首元素的地址,他们都相等
int a[5]={1,2,3,4,5};
printf(\
printf(\ printf(\
printf(\ printf(\printf(\
printf(\printf(\结果: a=12ff34 &a=12ff34
*&a=12ff34 ---*与&消掉,*&a=a=0x12ff34 &a[0]=12ff34
*&a[0]=1 ---*与&消掉,*&a[0]=a[0]=1
*(&a[0])=1 ---*与&消掉,*(&a[0])=*&a[0]=a[0]=1
*((int *)(&a))=1 ---*与&之间有个强制类型转换(int *),无法直接消掉,所以按照括号次序来运算(int *)(&a)=0x12ff34, *((int *)(&a))=*(0x12ff34)=1
*(*(&a))=1 ---*与&消掉,*(*(&a))=*a=1
D. 指针数组:
定义:基类型 *数组名[]
使用:像普通的数组一样使用,数组名代表首地址,数组名[0]表示第一个元素的内容,以此类推。
常见的是字符串数组,例如: char *Names[]= {
Bill, Sam, Jim };
实际内存中保存的就是
即首地址0x12ff0c{0x00423018,0x0042f2f4,0042201c},其中0x00423018地址所保存的就是”Bill”,所以数组名Name=0x12ff0c, &Name=0x12ff0c,*Name=0x00423018,**Name=0x42
printf(\ printf(\ printf(\
printf(\ printf(\printf(\printf(\printf(\printf(\printf(\
printf(\ printf(\结果是
Name=&Name=*&Name=&Name[0]=0x12ff0c
*Name=Name[0]=*&Name[0]=*(&Name[0])=(*((int *)(&Name)))=(*(*(&Name)))=0x00423018 **Name=*Name[0]=0x42
注意!指针是一级,数组是又一级,所以指针数组是二级指针,定义对应的指针变量要用二级指针,比如 int **p=Name; 不能直接用int *p=Name
5. 常量的定义和指针常量的定义及使用:
1.常量的定义:
const int a=10; //在其他地方不允许修改a的值,否则会编译不通过. 也可以写成 int const a=10; //一样的 2.指针常量的定义和使用:
有3种定义: const int *pi; 和 int const *pi; 以及 int * const pi; 1)前两种情况一样的,没有区别。
1) 如果const 修饰在*pi前(前2种情况)则不能改的是*pi(即不能 类似这样:*pi=50;赋值)而不是指pi.
2) 如果const 是直接写在pi前(后一种情况)则pi不能改(即不能类似 这样:pi=&i;赋值)。
6. 函数参数传递的4种类型:
1.值传递
void Exchg1(int x, int y) {
int tmp; tmp = x; x = y; y = tmp;
printf(\ }
main() {
int a = 4,b = 6; Exchg1(a, b);
printf(\ return(0); }
2.地址传递
void Exchg2(int *px, int *py) {
int tmp = *px; *px = *py;
*py = tmp;
printf(\ }
main() {
int a = 4; int b = 6;
Exchg2(&a, &b);
printf(\ return(0); }
3.引用传递
void Exchg3(int &x, int &y) {
int tmp = x; x = y; y = tmp;
printf(\ }
main() {
int a = 4; int b = 6; Exchg3(a, b);
printf(\ return(0); }
4.变长参数传递:使用省略号…指定参数表 使用的宏及其定义(x86中): #define va_start _crt_va_start #define va_arg _crt_va_arg #define va_end _crt_va_end
typedef char * va_list;
#define _ADDRESSOF(v) ( &(v) )
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 )
实例:
#include \