每天进步:2014年11月几篇
2014-11-02
C语言中的函数对应汇编中的子程序。
c语言中,子程序返回值一般用寄存器AX传递,临时变量大都保存在栈段中。
调用函数前,会先把要传递给函数的参数入栈,然后CPU把当前的IP寄存器入栈,以便函数调用完后返回时用。
然后CALL
进入函数。进入后先把BP寄存器入栈,再MOV BP,SP
。函数执行过程中BP的值从这一刻开始一般不变。
如果函数中有变量,会继续往栈顶写入。
用BP作为函数栈中的基准指针来读取函数的参数或变量。
例如BP+4
就是函数传进来的第一个参数,BP+6
是第二个……以此类推。
BP - n
(n是正整数)一般是函数内的临时变量。
常量一般保存在数据段(段地址为DS),偏移地址一般是一个常数不是内存中的值。
函数中的指针和变量没有本质的区别,在汇编看来都是相同的数据,一般都保存在内存中。但是意义上不同:
普通变量一般是做计算用,直接取了可以用;
指针变量除了本身保存在内存中做普通变量用外,还有间接寻址的作用,一般会把它的值先移到BX或DI、SI寄存器中,然后寻址找出相关内存中的数据例如[BX]
。
用指针寻址多做一步所以比较慢。
以上原理仅适用于CPU实模式下。
贴一个用C语言写的printf
函数,仅实现了显示%d
,%c
功能,可以接收不定量参数。
void nprintf(char *p, ...)
{
int num,j;
char c[20];
int count = 0;
int i_out = 0;
int i;
for(i=0; p[i]!='\0'; i++){
if(p[i]== '%'){
if(p[i+1] == 'd'){
count++;
num = *(int far *)(_SS*0x10000+_BP+4+2*count);
for(j=0; num!=0; num/=10){
c[j++] = num % 10 + 0x30;
}
while(j != 0){
*(char far *)(0xb8000000+160*12+2*i_out++) = c[--j];
}
i++;
continue;
}
if(p[i+1] == 'c'){
count++;
*(char far *)(0xb8000000+160*12+2*i_out++) = *(char far *)(_SS*0x10000+_BP+4+2*count);
i++;
continue;
}
}
*(char far *)(0xb8000000+160*12+2*i_out++) = p[i];
}
}
main(){
nprintf("char: %c, num: %d, hehe%c.", 'H', 31415, '3');
}
2014-11-05
windows窗口编程原理:
GetMessage
检查系统消息队列中的MSG
结构,
MSG
第一个字段为消息发向的窗口句柄,用其同自己第2个参数做比较,若MSG
是发送给自己接收的,则将队列中的MSG
相关字段写到自己第一个MSG
指针指向的内存区域。
DispatchMessage
函数以GetMessage
写好的MSG
结构前四个字段作为参数,调用窗口类的回调函数(窗口过程),回调函数会根据传进来的参数进行相应的处理。
比如,鼠标左键点击窗口的关闭按钮松开时候,windows系统会把这个点击事件封装成一个MSG
结构,其中记录了点击这一事件的全部信息。
包括被点击窗口的——
- 窗口句柄
- 事件类型:
WM_LBUTTONUP
(等效于十六进制的202) - 详细参数
- 消息放入队列的时间
- 鼠标坐标
窗口所属的线程调用GetMessage
函数,会获得这个MSG
结构并复制存储,线程调用DispatchMessage
函数,该函数会调用窗口所属的窗口类的窗口过程(也叫回调函数,实际就是一个子程序)来处理这个点击事件。
窗口过程中对WM_LBUTTONUP
事件类型做出处理,比如关闭窗口释放资源等操作。
整个过程中,事件在内存中是以MSG
结构的形式存储的,相关函数也是根据MSG
结构对事件进行判断和处理的。
对窗口事件的捕获并进行封装成MSG
结构是windows操作系统来完成的,对窗口过程的回调也是windows操作系统完成的。这些我们在编程时不必考虑细节。
但是为了让windows系统能够正确的找到相应的窗口类的窗口过程,在建立窗口类的时候我们需要指定所建立的窗口类的回调函数地址。
我们调用系统提供的RegisterClassEx
函数来建立窗口类,这个函数需要知道我们建立的窗口类的相关属性信息,我们要把相关信息作为参数传给它。
具体的:
这个函数接收一个包含将要建立窗口类属性信息的WNDCLASSEX
结构作为参数。 WNDCLASSEX
结构中有一个字段是lpfnwndproc
,这个字段的内容即所建立的窗口类的回调函数地址。
由同一个窗口类创建出来的所有窗口对象都使用一个窗口回调函数。
还有一个SendMessage
函数能够直接给窗口对象发送消息,这个函数的第一个参数是所发送的消息的目的窗口对象的句柄,第二个参数是窗口事件类型。
而PostMessage
函数能够往相关窗口对象消息队列中发送消息事件。
2014-11-06
windows下环境变量的设置
%变量名字%
会替换成相应变量代表的字符串。
如在命令行下echo %path%
可以输入path
变量的字符串。
源程序中include文件的默认查找路径在include
变量中, 可以用set include=“路径”
设置,用echo %include%
查看。
lib
变量是源程序中includelib
的默认查找路径。