C++中的逻辑运算符&&和||

a&&(b=b+2,c=c+3)
cmp DWORD PTR _a$[ebp], 0
je SHORT $L221
mov eax, DWORD PTR _b$[ebp]
add eax, 2
mov DWORD PTR _b$[ebp], eax
mov ecx, DWORD PTR _c$[ebp]
add ecx, 3
mov DWORD PTR _c$[ebp], ecx
if(a){b=b+2;c=c+3;}
cmp DWORD PTR _a$[ebp], 0
je SHORT $L221 ;&&->je
mov eax, DWORD PTR _b$[ebp]
add eax, 2
mov DWORD PTR _b$[ebp], eax
mov ecx, DWORD PTR _c$[ebp]
add ecx, 3
mov DWORD PTR _c$[ebp], ecx
a||(b=b+2,c=c+3);
cmp DWORD PTR _a$[ebp], 0
jne SHORT $L221 ;||->jne
mov eax, DWORD PTR _b$[ebp]
add eax, 2
mov DWORD PTR _b$[ebp], eax
mov ecx, DWORD PTR _c$[ebp]
add ecx, 3
mov DWORD PTR _c$[ebp], ecx

&&,||最终会被翻译成je和jne跳转
完全等价于if语句,不过当逻辑表达式作为判断条件时

if(a&&b){}

会在后面加上test eax,eax作为jmp的依据

i++,i+=1,i=i+1 哪个效率更高?

今天看到这么一道题:

i++,i+=1,i=i+1哪个效率更高?为什么

给出的解答是:

x=x+1最低,执行过程:
1)读取右边x的地址
2)x+1
3)读取左边x的地址
4)将右值给左边的x(编译器并不认为左右x的地址相同) (编译器不会这么笨吧,两个x还能有不一样的地址??)

x+=1次之,过程:
1)读取右边x的地址
2)x+1
3)将得到的值给x(因为x的地址已经读出)

x++的效率最高,过程:
1)读取右边x的地址
2)x自增1

所以x++的效率最高….

怀疑~~

不知道上面所说的过程是从什么角度来评价效率的

按我说,效率应该从产生的指令数和指令类型综合起来说

研究下列c++代码:

int
main(int,char**)
{
int i=1;
i++;
i+=1;
i=i+1;
return 0; 
}

cl.exe产生的汇编代码如下:

; Line 5
mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax
; Line 6
mov ecx, DWORD PTR _i$[ebp]
add ecx, 1
mov DWORD PTR _i$[ebp], ecx
; Line 7
mov edx, DWORD PTR _i$[ebp]
add edx, 1
mov DWORD PTR _i$[ebp], edx

g++产生的汇编代码如下:

; Line 5
leal -4(%ebp), %eax
incl (%eax)
; Line 6
leal -4(%ebp), %eax
incl (%eax)
; Line 7
leal -4(%ebp), %eax
incl (%eax)

编译器生成的汇编代码可能是经过不同成都优化的
用ollydbg查看最终exe的执行代码如下:

cl.exe产生的exe

g++产生的exe代码

可见无论cl还是g++对i++,i+=1,i=i+1的翻译都是一样的

只是cl将之翻译成3条指令,g++翻译成两条
所以说所以在上面这种情况下,i++,i+=1,i=i+1的效率是一样的!

我的小程序ZoOmeAsure

zoomeasure

为了给ZoOmeAsure(ZA)截图还真费了一番功夫,因为它就是我最常用的截图工具。。

ZoOmeAsure=Zoom & Measure。来自Photoshop中的两个工具: 放大镜和尺子。

因为在做网页时需要精确测量尺寸,经常要做的是: 截屏->打开PS->Zoom->Measure打开Photoshop代价巨大,而我所找到的屏幕尺子大多都是模拟真实的尺子,很不方便所以就写了个小工具来完成这个工作ZA启动快速,可以整个屏幕截图,然后操作就跟PS中一样了,基本的快捷键和PS默认基本相同可以保存局部为图片,也可以直接将局部拷贝到剪贴板中目前还没有发布,正在研究滚动截屏 (我舍友说,他最需要的就是一个能滚动截屏的小截图工具)

通过汇编代码研究C++

首先树立以下几个概念:

  • 编译器 compiler
  • 链接器 linker
  • 编译时期 compile time
  • 运行时期 runtime
  • 数据段 data segment/ds
  • 代码段 code segment/cs
  • 语法 syntax
  • 语义 semantics
  • 栈 stack
  • 堆 heap

全局变量

int global_var = 5;

int
main(int argc,char** argv)
{
static int i=3;
i=7;
return 0;
}
PUBLIC          ; global_var
_DATA SEGMENT

;静态变量和全局变量在数据段分配
DD 05H          ; global_var
DD 03H
_DATA ENDS
PUBLIC _main
_TEXT SEGMENT
_main PROC NEAR
push ebp
mov ebp, esp

; 直接对数据段内存赋值
mov DWORD PTR , 7 
xor eax, eax
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END

类的静态成员变量

class MyClass
{
public:
       int static       STATIC_VAR;
};

int MyClass::STATIC_VAR = 7;

int
main(int argc,char** argv)
{
MyClass::STATIC_VAR = 6;
return 0;
}
PUBLIC         ; MyClass::STATIC_VAR
_DATA SEGMENT

;类的静态成员同样在数据段分配分配内存
DD 07H         ; MyClass::STATIC_VAR
_DATA ENDS


PUBLIC _main
_TEXT SEGMENT
_main PROC NEAR
push ebp
mov ebp, esp

;直接对数据段内存赋值
mov DWORD PTR , 6 ; MyClass::STATIC_VAR
xor eax, eax
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END

枚举

enum COLOR{
cl0,cl1,cl2,cl3,cl4,cl5,cl6,cl7,cl8,cl9,cl10,cl11,cl12,cl13,cl14,cl15,
cl16,cl17,cl18,cl19,cl20,cl21,cl22,cl23,cl24,cl25,cl26,cl27,cl28,cl29,cl30,
cl31,cl32,cl33,cl34,cl35,cl36,cl37,cl38,cl39,cl40,cl41,cl42,cl43,cl44,cl45,
cl46,cl47,cl48,cl49,cl50,cl51,cl52,cl53,cl54,cl55,cl56,cl57,cl58,cl59,cl60,
cl61,cl62,cl63,cl64,cl65,cl66,cl67,cl68,cl69,cl70,cl71,cl72,cl73,cl74,cl75,
cl76,cl77,cl78,cl79,cl80,cl81,cl82,cl83,cl84,cl85,cl86,cl87,cl88,cl89,cl90,
cl91,cl92,cl93,cl94,cl95,cl96,cl97,cl98,cl99,cl100,cl101,cl102,cl103,cl104,
cl105,cl106,cl107,cl108,cl109,cl110,cl111,cl112,cl113,cl114,cl115,cl116,
cl117,cl118,cl119,cl120,cl121,cl122,cl123,cl124,cl125,cl126,cl127,cl128,
cl129,cl130,cl131,cl132,cl133,cl134,cl135,cl136,cl137,cl138,cl139,cl140,
cl141,cl142,cl143,cl144,cl145,cl146,cl147,cl148,cl149,cl150,cl151,cl152,
cl153,cl154,cl155,cl156,cl157,cl158,cl159,cl160,cl161,cl162,cl163,cl164,
cl165,cl166,cl167,cl168,cl169,cl170,cl171,cl172,cl173,cl174,cl175,cl176,
cl177,cl178,cl179,cl180,cl181,cl182,cl183,cl184,cl185,cl186,cl187,cl188,
cl189,cl190,cl191,cl192,cl193,cl194,cl195,cl196,cl197,cl198,cl199,cl200,
cl201,cl202,cl203,cl204,cl205,cl206,cl207,cl208,cl209,cl210,cl211,cl212,
cl213,cl214,cl215,cl216,cl217,cl218,cl219,cl220,cl221,cl222,cl223,cl224,
cl225,cl226,cl227,cl228,cl229,cl230,cl231,cl232,cl233,cl234,cl235,cl236,
cl237,cl238,cl239,cl240,cl241,cl242,cl243,cl244,cl245,cl246,cl247,cl248,
cl249,cl250,cl251,cl252,cl253,cl254,cl255,cl256,cl257,cl258};

int
main(int argc,char** argv)
{
COLOR color = cl258;
color = cl2;
return 0;
}
PUBLIC _main
_TEXT SEGMENT
_color$ = -4
_main PROC NEAR
push ebp
mov ebp, esp
push ecx

; 枚举类型最终是以无符号整数实现的
; COLOR color = cl258;
mov DWORD PTR _color$[ebp], 258

; color = cl2;
mov DWORD PTR _color$[ebp], 2

xor eax, eax
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END

类的构造函数

class MyClass
{
public:
     int i;
     int j;
     int k;
     MyClass();
     ~MyClass();
     void f(int i);
};
MyClass::MyClass(){
this->i=7;
this->j=9;
this->k=11;
}
MyClass::~MyClass(){}
void MyClass::f(int j)
{
this->j = j;
__asm{
     mov this,5
}
}

int
main(int argc,char** argv)
{
MyClass *my = new MyClass();
my->f(3);
return 0;
}
;-----------------------------------------------
; MyClass::MyClass
;-----------------------------------------------
PUBLIC        ; MyClass::MyClass
_TEXT SEGMENT
_this$ = -4
PROC NEAR       ; MyClass::MyClass

push ebp
mov ebp, esp
push ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov DWORD PTR [eax], 7
mov ecx, DWORD PTR _this$[ebp]
mov DWORD PTR [ecx+4], 9
mov edx, DWORD PTR _this$[ebp]
mov DWORD PTR [edx+8], 11      ; 0000000bH
mov eax, DWORD PTR _this$[ebp]
mov esp, ebp
pop ebp
ret 0
ENDP        ; MyClass::MyClass
_TEXT ENDS


;-----------------------------------------------
; MyClass::~MyClass
;-----------------------------------------------
PUBLIC        ; MyClass::~MyClass
_TEXT SEGMENT
_this$ = -4
PROC NEAR       ; MyClass::~MyClass
push ebp
mov ebp, esp
push ecx
mov DWORD PTR _this$[ebp], ecx
mov esp, ebp
pop ebp
ret 0
ENDP        ; MyClass::~MyClass
_TEXT ENDS


;-----------------------------------------------
; MyClass::f()
;-----------------------------------------------
PUBLIC        ; MyClass::f
_TEXT SEGMENT
_j$ = 8
_this$ = -4
PROC NEAR       ; MyClass::f
push ebp
mov ebp, esp
push ecx
push ebx
push esi
push edi
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov ecx, DWORD PTR _j$[ebp]
mov DWORD PTR [eax+4], ecx
mov DWORD PTR _this$[ebp], 5
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 4
ENDP       ; MyClass::f
_TEXT ENDS


;-----------------------------------------------
; 主函数
;-----------------------------------------------
PUBLIC _main

;new操作符号就是一个函数
EXTRN        ; operator new
_TEXT SEGMENT
_my$ = -4
$T254 = -8
_main PROC NEAR
; Line 27
push ebp
mov ebp, esp
sub esp, 12
; MyClass *my = new MyClass();

; 调用new()在堆中分配一块内存,大小为MyClass左右成员变量大小之和,this指针在计算之内
; 12入栈,12是new的参数,由于编译时期MyClass已知,所以掉用new的时候不用给出参数,由编译器自己计算
push 12
call        ; operator new
add esp, 4

; new()将在堆中分配的内存块的首地址放在EAX,然后将EAX中的内容(首地址)放入变量my中
mov DWORD PTR $T254[ebp], eax

; 检查new()是否分配失败,如果失败则跳转到$L255
cmp DWORD PTR $T254[ebp], 0
je SHORT $L255

; 如果分配成功,以new()返回的首地址为参数调用MyClass的构造函数
mov ecx, DWORD PTR $T254[ebp]
call       ; MyClass::MyClass
mov DWORD PTR -12+[ebp], eax
jmp SHORT $L256
mov DWORD PTR -12+[ebp], 0
mov eax, DWORD PTR -12+[ebp]
mov DWORD PTR _my$[ebp], eax
; my->f(3);
push 3
mov ecx, DWORD PTR _my$[ebp]
call       ; MyClass::f


xor eax, eax
mov esp, ebp
pop ebp
ret 0
_main ENDP

指针和地址

int main(int argc, char *argv[])
{
int i=7;
char c = 'c';
int *pi=&i; 
char *pc=&c;
pi = (int*)pc;

return 0;
}
PUBLIC _main
_TEXT SEGMENT
_i$ = -12
_c$ = -8
_pi$ = -4
_pc$ = -16
_main PROC NEAR

push ebp
mov ebp, esp
sub esp, 16

; int i = 7;
mov DWORD PTR _i$[ebp], 7

; char c = "c";
mov BYTE PTR _c$[ebp], 99

; int *pi = &i;
lea eax, DWORD PTR _i$[ebp]
mov DWORD PTR _pi$[ebp], eax

; char *pc = &c;
lea ecx, DWORD PTR _c$[ebp]
mov DWORD PTR _pc$[ebp], ecx

; pi = (int*)pc; 
mov edx, DWORD PTR _pc$[ebp]
mov DWORD PTR _pi$[ebp], edx

xor eax, eax
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END

更新:
推荐下面这本书,对理解c++如何实现各种语言特性很有帮助

[C++反汇编与逆向分析技术揭秘](https://book.douban.com/subject/6849800/)

我的小程序NuTs IPScanner

扫描局域网内所有主机(禁止ping的主机无法显示)起初是为了查当前网段可用的IP,增加手动设置IP的成功率,之后有了 NuTs IWantIP就基本不用了不过用来查主机与IP映射还是很快的程序采用多线程,速度很快~

NuTs Login&Out

科大专用上网登录程序学校校园网实行实名制,每个同学上网都要到特定网页输入学号和密码,这本来挺好的,可问题是,当用户关机的时候如果不注销帐号,那么当下次开机,IP改变后,无法访问任何网页,提示说帐号被上一个IP占用,而上一个IP如果恰好又被别人使用,那么那个人就可以使用你的帐号上网. 而你只有哭的份了 (幸好学校上网不收费)于是我写了这个登录/注销程序. 程序会在关机/重启/注销时自动注销上网帐号,这样就可以避免上述问题.程序还可以定时检测网络连通性(ping baidu.com)并刷新arp缓存. 这样可以解决arp欺骗导致的无法上网的问题.(宿舍楼的arp欺骗很严重~)这个程序还是很好用滴,不过在离开科大后就再也用不上了.科大的同学可以在 http://city.ibeike.com 的编程板块(还是软件,我忘了)找到下载

Scroll to top