【1】do{}while(0)
#define cerror(str, n) do{ perror(str); exit(n);}while(0)
好处,主要是与if连用的时候,首先,要用{}扩起来,否则可能会出现下列情况:
#define cerror(str,n) perror(str); exit(n);
if(n>0)
cerror(str,n):
于是替换以后变成
if(n>0)
perror(str);
exit(n);
另外,必须用do while是因为,如果if后面有else,那么会出现:
替换前:
#define cerror(str,n) {perror(str), exit(n);}
if(n>0)
cerror(str,n);
else
...
替换后:
if(n>0)
{perror(str), exit(n);}
;
else
...
多出来一个分号,平时多一个分号不要紧,但是在这里,却把if-else打断了,编译报错。
【2】循环可以实现跳转:
bool Execute()
{
// 分配资源
int *p = new int;
bool bOk(true);
do
{
// 执行并进行错误处理
bOk = func1();
if(!bOk) break;
bOk = func2();
if(!bOk) break;
bOk = func3();
if(!bOk) break;
// ..........
}while(0);
// 释放资源
delete p;
p = NULL;
return bOk;
}
实现了goto的功能:
bool Execute()
{
// 分配资源
int *p = new int;
bool bOk(true);
// 执行并进行错误处理
bOk = func1();
if(!bOk) goto errorhandle;
bOk = func2();
if(!bOk) goto errorhandle;
bOk = func3();
if(!bOk) goto errorhandle;
// ..........
// 执行成功,释放资源并返回
delete p;
p = NULL;
return true;
errorhandle:
delete p;
p = NULL;
return false;
}
【3】
用一句话实现以下功能:
if(n!=0)
n=1;
else
n=0;
当然可以用n=(n==0)?0:1;实现,但是n=!!n;是否更吊呢!
【4】
lea做简单运算。转的:
比如你用local在栈上定义了一个局部变量LocalVar,你知道实际的指令是什么么?一般都差不多像下面的样子:
push ebp
mov esp, ebp
sub esp, 4
现在栈上就有了4各字节的空间,这就是你的局部变量。
接下来,你执行mov LocalVar, 4,那么实际的指令又是什么?是这样:
mov dword ptr [ebp-4], 4
于是,这个局部变量的“地址”就是ebp-4——显然,它不是一个固定的地址。现在需要将它的“地址”作为参数传给某个函数,你这样写:
invoke/call SomeFunc, addr LocalVar
实际生成的指令是:
lea eax, [ebp-4]
push eax
call SomeFunc
当然,你也可以写成:
mov eax, ebp
sub eax, 4
push eax
call SomeFunc
看到了,这里多了一条指令。这就是lea的好处。于是,lea又多了一个非常美妙的用途:作简单的算术计算,特别是有了32位指令的增强寻址方式,更是“如虎添翼”:
比如你要算EAX*4+EBX+3,结果放入EDX,怎么办?
mov edx, eax
shl edx, 2
add edx, ebx
add edx, 3
现在用lea一条指令搞定:
lea edx, [ebx+eax*4+3]
lea的英文解释是:Load Effective Address.(加入有效地址,开始迷惑效地址是什么???既然是有效地址与mov ax , [address] 又有什么不同呢?其实他们都是等效的。 后来知道实际上是一个偏移量可以是立即数,也可以是经过四则运算的结果,更省空间,更有效率)