linha0 发表于 2011-7-4 12:10:10

有关子程序功能设计的问题

本帖最后由 linha0 于 2011-7-5 17:41 编辑

一个子程序的功能:
1、应该是尽量的细化好呢?
2、还是尽量宏观化好呢?(不知怎么样形容,只好用宏观)

比如,转化大小写的功能:
用子程序来表示


1、用单个字母做参数,然后在子程序中转化,并返回结果;


2、不论要转化的是字母还是字符串,一律当作字符串处理;

具体实现:
参数(起始地址,字符串长度,字符串地址),然后在子程序中直接转化字符串,不用返回


这应该怎么选择好呢?
是具体问题,具体选择
还是,所有问题统一解决


winddyj 发表于 2011-7-4 13:13:38

回答这个问题前,还是要思考下子程序的作用.把功能重复的代码拿出来,以便重复利用
如果楼主的这两个子程序都可以实现这个目的,那用哪种都可以了

linha0 发表于 2011-7-4 16:08:06

大概因为之前有学过一点微软的编程知识,但又因为学得不好,所以就有点“断章取义”地造成了前面 的那 两个 问题;

下面就第十章的10.11和10.12两个例题来说:

linha0 发表于 2011-7-4 16:27:03

本帖最后由 linha0 于 2011-7-4 17:45 编辑

在做10.11的时候,程序是这样设计的:

assume cs:code,ds:data

data segment
db 'conversation',0
data ends

code segment
start:      
                mov ax,data
                mov ds,ax
               
                mov si,0
                mov cx,12
      s:      mov al,
                call uppercase                ;调用子程序1
                mov ,al
                              
                inc si
                loop s
               
                mov ax,4c00h
                int 21h
               
uppercase:                                        ;子程序1:利用AL保存参数,然后在子程序中转化,最后返回AL
                and al,11011111b
                ret

code ends
end start

1、最先是以功能最小化为目的,但是这样做,每次调用子程序1都需要重写一段循环的指令。感觉太麻烦了,于是就用子程序2来代替子程序1:
uppercase2:      
                mov al,
                and al,11011111b
                mov ,al
                inc si
                loop uppercase2
                ret
2、这样解决了子程序1的代码可重用性的问题了。但是在接下来的10.12中,需要把子程序2的功能改造成另一种相似的功能。子程序3:
uppercase3:      
                mov cl,
                mov ch,0
                jcxz ok;不需要在子程序外面再设置CX的值
               
                and cl,11011111b
                mov ,cl
                inc si
               
      ok:      ret

3、如果还需要再改造一个相似功能的子程序;又或者,在复制“and cl,11011111b” 这类功能相同代码相似的指令时出了错,会很麻烦的。如果这种子程序再多一些呢?


4、于是,就有了最终版程序代码(这让我想起了我的一个想当年的同事)
assume cs:code,ds:data

data segment
db 'conversation',0
data ends

code segment
start:
            mov ax,data
            mov ds,ax

            mov si,0
            mov cx,12
            call uppercase2;调用子程序2,10.11题
                       
            mov ax,4c00h
            int 21h

uppercase: ;子程序1:利用AL保存参数,然后在子程序中转化,最后返回AL
            and al,11011111b
            ret

uppercase2:
            mov al,
            call uppercase;调用子程序1
            mov ,al
            inc si
            loop uppercase2
            ret

uppercase3:
            mov cl,
            mov ch,0
            jcxz ok;不需要在子程序外面再设置CX的值

                        mov al,cl
            call uppercase;调用子程序1
            mov ,al
            inc si
                        jmp short uppercase3

      ok:        ret
code ends
end start
5、可是,这个代码怎么看怎么不爽。于是,又学我的同事在后面再加上“完美”两个字,最终完善版(搞笑一下):assume cs:code,ds:data

data segment
db 'conversation',0
data ends

code segment
start:
            mov ax,data
            mov ds,ax

            mov si,0
            mov cx,12
            call uppercase2;调用子程序2,10.11题
                       
            mov ax,4c00h
            int 21h

uppercase: ;子程序1:利用AL保存参数,然后在子程序中转化,最后返回AL
            and byte ptr ,11011111b
            ret

uppercase2:
            call uppercase;调用子程序1
            inc si
            loop uppercase2
            ret

uppercase3:
            mov cl,
            mov ch,0
            jcxz ok;不需要在子程序外面再设置CX的值

            call uppercase;调用子程序1
            inc si
                        jmp short uppercase3

      ok:        ret
code ends
end start

6、再次删掉一些碍眼的东东后,这下爽快了。可是,我回头一看,于是彻底的{:2_36:}………………

linha0 发表于 2011-7-4 17:53:29

最终,问题又回到了起点。

子程序的功能设计,要怎么去设计呢?

要怎样去保证代码的可重用性?

要不要给代码留下可以扩展的可能呢?

要不要形成自己的一套编程习惯呢?(按中国的说法:叫套路;按老外的说法:叫框架)

小甲鱼 发表于 2011-7-5 05:48:34

比如,转化大小写的功能:
用子程序来表示


1、用单个字母做参数,然后在子程序中转化,并返回结果;
我觉得,具体情况具体分析。任何时候设计程序都要考虑两个方面:最恶劣的计算机环境(例如256MB内存……)和用户的真实体验。每转换一个字母调用一次子程序的确规范,但消耗内存比较严重,不推荐。

linha0 发表于 2011-7-5 17:38:26

本帖最后由 linha0 于 2011-7-5 17:44 编辑

我也觉得呢!不过回过头来,再重新整理一下思路,发现:and al,11011111b   这个指令功能已经是最小的核心单元了。我竟然还跑去封装它,这简直就是吃饱撑着了的:lol

不过我还是有个疑问,子程序的调用过程如下(俺的理解):
1、执行Call指令,入栈并跳转到子程序内存段。(这时占有栈段一小部份内存空间)

2、执行子程序的相应代码指令。(程序加载时就已经占有的内存空间)

3、执行Ret指令,出栈并返回主程序。(同时还原已占有的栈段空间)

按这样的理解,调用子程序时占用的内存空间并不会增加多少才对。但是,如果调用子程序的频率过高的话,消耗的应该是CPU资源吧?

我也不知道这样分析对不对,请指正!
页: [1]
查看完整版本: 有关子程序功能设计的问题