我的小程序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 的编程板块(还是软件,我忘了)找到下载

C++函数调用中的引用和指针

C++初学者对函数调用中的引用总是感到十分迷惑

下面就研究一下

先看下面三个函数

void f1(int a,intb) //按值传递
{
     a=0;
     b=3;
}

void f2(int &a,int &b) //按引用传递
{
     a=0;
     b=3;
}

void f3(int *a,int *b) //按指针传递
{
     *a=0;
     *b=3;
}

要想知道他们之间的区别,最好的方法是看看编译器究竟干了什么
用cl.exe 的-Fa参数,生成对应源代码的汇编代码,摘要如下

按值传递

PROC NEAR 
push ebp
mov ebp, esp
;直接将压入栈的2个参数赋值为0和3
mov DWORD PTR _a$[ebp], 0
mov DWORD PTR _b$[ebp], 3
pop ebp
ret 0

按引用传递

PROC NEAR

push ebp
mov ebp, esp
;将压入栈的参数作为指针,将0和3赋值给指针所指向的内存单元
mov eax, DWORD PTR _a$[ebp]
mov DWORD PTR [eax], 0
mov ecx, DWORD PTR _b$[ebp]
mov DWORD PTR [ecx], 3
pop ebp
ret 0

按指针传递

PROC NEAR

push ebp
mov ebp, esp
;可以看到,按引用传递和按指针传递的汇编代码一模一样
;但是使用引用,我们不必再用星号解引用了,这样提高了代码的可读性
;语言层面,引用的用法和对象一样;在二进制层面,引用一般都是通过指针来实现的,
;只不过编译器帮我们完成了转换
mov eax, DWORD PTR _a$[ebp]
mov DWORD PTR [eax], 0
mov ecx, DWORD PTR _b$[ebp]
mov DWORD PTR [ecx], 3
pop ebp
ret 0

引用既具有指针的效率,又具有变量使用的方便性和直观性

C++、Java、Delphi类继承的对比

总体来说

  • c++: 完全的控制,极大的灵活性,灵活带来的复杂
  • java:比c++"保守",虚拟机风格的体系结构
  • delphi:很保守

inclusion/using clause

#include <iostream>
using namespace std;
import java.io.*;
uses windows,system,sysutils;

inheritance
class Child:[public | protected | private] Fahter,public Mother{
            ...
}

C++是这三种语言中继承最为复杂的.
分为 public,protected,private继承,同时支持真正的多继承

public继承(又称类型继承)和java的继承一样,保持父类的访问控制

protected继承将父类public成员改变为protected的

private继承(又称实现继承)不直接支持父类的公有接口,而提供自己的公有接口

所以private继承中,子类将父类中原先的protected成员和public成员都置为private的
所以原则上private继承中的子类应该是继承树中的叶节点,它只有private和public成员而
没有protected成员.它不应该再被继承,类似于Java中的final class

class Child extends Father implements IInterface{
            ...
}
TChild = class(TFather,IInterfacedObject)
            ...
end;

java 和 delphi 的继承相似,都是单继承同时可以实现多个接口

Access Control/Organization

class Foo{
   private:
    int i;
             int j;
             void f();
   protected: 
             int k;
   public: 
             int o;
}

class Foo /* extends Object */ {
  private
             int i;
             int j;
             void f(){...};
   protected
             int k;
   public
             int o;
}
TFoo = class(TObject)
   private 
             i:Integer;
             j:Integer;
   protected
             k:Integer;
   public
             o:Integer;
   publicshed
   property
             Tag:Integer read i write i;
end;

如果不给出访问控制,
c++默认是private
java默认是包内可见的
delphi默认是public的(单元内可见?)

c++的访问控制和代码管理最为丰富:
可以通过#include包含c/cpp头文件,提供向c的兼容
同时可以使用名字空间防止名字冲突,并且像c一样将代码分为头文件和实现文件
同时丰富性也带来了复杂性.使得c++的文件组织没有java和delphi清晰

java提供了松散的代码组织方式–包(package),而delphi提供了单元的代码组织方法
这两种组织方法相似,都是给了我们一个存放一组相关类的地方.而这个地方,在java中
是一个文件系统上的文件夹,在delphi中是一个单元文件
相比之下,我还是喜欢Delphi的组织方法:当类很多的时候java包中的文件变得既多又不好管理

虚函数 vs 动态函数

C++中有虚函数。而Delphi中既有虚函数还有动态函数。二者在语义上是等价的。

Virtual and dynamic methods are semantically equivalent. They differ only in the implementation of method-call dispatching at runtime.

区别在于虚函数优化了速度,而动态函数优化了代码大小

Virtual methods optimize for speed, while dynamic methods optimize for code size.

In general, virtual methods are the most efficient way to implement polymorphic behavior.

总体上来讲,虚函数是实现多态行为的最有效的方法

Dynamic methods are useful when a base class declares many overridable
methods which are inherited by many descendant classes in an application, but only
occasionally overridden.

当基类声明了很多可重写但是很少重写的方法时使用动态函数,
这样可一减小代码大小。在设计Framework时常使用这个技术

Posts navigation

1 2 3 4 5 6
Scroll to top