<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    2005年12月28日

         摘要: 背景: 攔截器是現在很多程序必須的一個東西。比如要在某個方法的前后做些處理,在一些特定的情況下可能會導致大量的重復代碼。而假如我們擁有了類似攔截器一樣的東西,那我們就可以任意在自己希望的方法的執行前后做我們自己的處理,比如日志,取得參數或者是事務等。   實現: 1.首先定義一個業務接口  1/** *//** 3 *&nbs...  閱讀全文

    posted @ 2005-12-28 19:02 李嵐 閱讀(561) | 評論 (0)編輯 收藏


    2005年12月21日

    我與父親不相見已二年余了,我最不能忘記的是他的背影。那年冬天,祖母死了,父親的差使也交卸了,正是禍不單行的日子,我從北京到徐州,打算跟著父親奔喪回家。到徐州見著父親,看見滿院狼藉的東西,又想起祖母,不禁簌簌地流下眼淚。父親說,“事已如此,不必難過,好在天無絕人之路!”回家變賣典質,父親還了虧空;又借錢辦了喪事。這些日子,家中光景很是慘淡,一半為了喪事,一半為了父親賦閑。喪事完畢,父親要到南京謀事,我也要回北京念書,我們便同行。到南京時,有朋友約去游逛,勾留了一日;第二日上午便須渡江到浦口,下午上車北去。父親因為事忙,本已說定不送我,叫旅館里一個熟識的茶房陪我同去。他再三囑咐茶房,甚是仔細。但他終于不放心,怕茶房不妥帖;頗躊躇了一會。其實我那年已二十歲,北京已來往過兩三次,是沒有甚么要緊的了。他躊躇了一會,終于決定還是自己送我去。我兩三回勸他不必去;他只說,“不要緊,他們去不好!”我們過了江,進了車站。我買票,他忙著照看行李。行李太多了,得向腳夫行些小費,才可過去。他便又忙著和他們講價錢。我那時真是聰明過分,總覺他說話不大漂亮,非自己插嘴不可。但他終于講定了價錢;就送我上車。他給我揀定了靠車門的一張椅子;我將他給我做的紫毛大衣鋪好坐位。他囑我路上小心,夜里警醒些,不要受涼。又囑托茶房好好照應我。我心里暗笑他的迂;他們只認得錢,托他們直是白托!而且我這樣大年紀的人,難道還不能料理自己么?唉,我現在想想,那時真是太聰明了!我說道,“爸爸,你走吧。”他望車外看了看,說,“我買幾個橘子去。你就在此地,不要走動。”我看那邊月臺的柵欄外有幾個賣東西的等著顧客。走到那邊月臺,須穿過鐵道,須跳下去又爬上去。父親是一個胖子,走過去自然要費事些。我本來要去的,他不肯,只好讓他去。我看見他戴著黑布小帽,穿著黑布大馬褂,深青布棉袍,蹣跚地走到鐵道邊,慢慢探身下去,尚不大難。可是他穿過鐵道,要爬上那邊月臺,就不容易了。他用兩手攀著上面,兩腳再向上縮;他肥胖的身子向左微傾,顯出努力的樣子。這時我看見他的背影,我的淚很快地流下來了。我趕緊拭干了淚,怕他看見,也怕別人看見。我再向外看時,他已抱了朱紅的橘子望回走了。過鐵道時,他先將橘子散放在地上,自己慢慢爬下,再抱起橘子走。到這邊時,我趕緊去攙他。他和我走到車上,將橘子一股腦兒放在我的皮大衣上。于是撲撲衣上的泥土,心里很輕松似的,過一會說,“我走了;到那邊來信!”我望著他走出去。他走了幾步,回過頭看見我,說,“進去吧,里邊沒人。”等他的背影混入來來往往的人里,再找不著了,我便進來坐下,我的眼淚又來了。近幾年來,父親和我都是東奔西走,家中光景是一日不如一日。他少年出外謀生,獨力支持,做了許多大事。那知老境卻如此頹唐!他觸目傷懷,自然情不能自已。情郁于中,自然要發之于外;家庭瑣屑便往往觸他之怒。他待我漸漸不同往日。但最近兩年的不見,他終于忘卻我的不好,只是惦記著我,惦記著我的兒子。我北來后,他寫了一信給我,信中說道,“我身體平安,惟膀子疼痛利害,舉箸提筆,諸多不便,大約大去之期不遠矣。”我讀到此處,在晶瑩的淚光中,又看見那肥胖的,青布棉袍,黑布馬褂的背影。唉!我不知何時再能與他相見!

    posted @ 2005-12-21 19:03 李嵐 閱讀(2203) | 評論 (19)編輯 收藏


    2005年11月23日

    前兩種方式webwork的wiki里有,就不多說了,點這里可以查看
    而以下的給出的思路是webwork mail list的討論的一種方案,應該是最好的一種方案。

    代碼1:

    public class SpringContainer implements Container {
        
    private
     ApplicationContext applicationContext;

        
    public SpringContainer(ServletContext servletContext) 
    {
            
    this.applicationContext =
     WebApplicationContextUtils.getWebApplicationContext(servletContext);
        }


        
    public SpringContainer(ApplicationContext applicationContext) {
            
    this.applicationContext =
     applicationContext;
        }


        
    /**
         * 
    @param key
         *            component class type or component name
         * 
    @return @throws

         *         ComponentNotFoundException
         
    */

        
    public Object getComponent(Object key) throws ComponentNotFoundException {
            
    if (applicationContext == null
    )
                
    throw new IllegalStateException("Spring Application context has not been set"
    );
            
    if (key == null
    )
                
    throw new ComponentNotFoundException("The component key can not be null"
    );
            
    if (key instanceof Class) 
    {
                Map beans 
    =
     applicationContext.getBeansOfType((Class) key);
                
    if (beans == null
    )
                    
    throw new ComponentNotFoundException("The container is unable to resolve single instance of " +
     ((Class) key).getName()
                            
    + ", none instances found"
    );
                
    if (beans.size() == 0 || beans.size() > 1
    )
                    
    throw new ComponentNotFoundException("The container is unable to resolve single instance of " +
     ((Class) key).getName()
                            
    + ", number of instances found was: " +
     beans.size());
                key 
    =
     beans.keySet().iterator().next();
            }

            
    return applicationContext.getBean(key.toString());
        }


        
    public void reload() {
            close();
            ((AbstractApplicationContext) applicationContext).refresh();
        }


        
    public void autowireComponent(Object bean) {
            ((AbstractApplicationContext) applicationContext).getBeanFactory().autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, 
    false
    );
        }


        
    public void close() {
            ((AbstractApplicationContext) applicationContext).close();
        }


    }

    代碼2:
    public class ComponentAutowireInterceptor implements Interceptor {


        
    public void destroy() 
    {
            
    // TODO Auto-generated method stub

        }


        
    public void init() {
            
    // TODO Auto-generated method stub

        }


        
    public String intercept(ActionInvocation invocation) throws Exception {
            Application.getInstance().getContainer().autowireComponent(invocation.getAction());
            
    return
     invocation.invoke();
        }


    }


    這幾段代碼,你不需要在spring里配置action,也不需要在xwork.xml里面配置external-ref。只要保證action引用的東東和spring里面同名就能夠auto wire by name了。

    原理:攔截器會在每個action之前調用autowireComponent(invocation.getAction())。這樣spring就會去自動組裝這個傳進來的action對象,而action對象里的屬性和spring里的bean id同名。所以spring就會自動將application.xml里對應的bean注射到action的屬性里去,從而達到把action按用戶希望的方式組裝起來的目的。

    如:
    appliaction.xml
        <bean id="myService">
            
    <property name="target">
                
    <bean class="myServiceDefaultImpl" autowire="byName">
              
    </property>
        
    </bean>

    xwork.xml
            <action name="myAction" class="myAction">
                
    <result name="success">/success.ftl</result>
            
    </action>

    Action:
    public class myAction extends ActionSupport {
        protected myService;
             .......

        }

    最后記得要在web.xml配上listener-class

    posted @ 2005-11-23 13:52 李嵐 閱讀(918) | 評論 (0)編輯 收藏


    2005年8月3日

    GDB使用指南 [ZZ]
     
    使用GDB:
    本文描述GDB,GNU的原代碼調試器。(這是4.12版1994年一月,GDB版本4。16)

     

    目錄:
    * 摘要: GDB的摘要
    * 實例: 一個使用實例
    * 入門: 進入和退出GDB
    * 命令: GDB 的命令
    * 運行: 在GDB下運行程序
    * 停止: 暫停和繼續執行
    * 棧: 檢查堆棧
    * 原文件: 檢查原文件
    * 數據: 檢查數據
    * 語言: 用不同的語言來使用GDB
    * 符號: 檢查符號表
    * 更改: 更改執行
    * GDB的文件 文件
    * 對象 指定調試對象
    * 控制GDB 控制
    * 執行序列: 執行一序列命令
    * Emacs: 使GDB和Emacs一起工作
    * GDB的bug:
    * 命令行編輯: 行編輯
    * 使用歷史記錄交互:
    * 格式化文檔: 如何格式化和打印GDB文檔
    * 安裝GDB :

    * 索引:

    GDB簡介:
    **************

    調試器(比如象GDB)能讓你觀察另一個程序在執行時的內部活動,或程序出錯時
    發生了什么。
    GDB主要能為你做四件事(包括為了完成這些事而附加的功能),幫助你找出程序
    中的錯誤。
    * 運行你的程序,設置所有的能影響程序運行的東西。

    * 保證你的程序在指定的條件下停止。

    * 當你程序停止時,讓你檢查發生了什么。

    * 改變你的程序。那樣你可以試著修正某個bug引起的問題,然后繼續查找另一
    個bug.

    你可以用GDB來調試C和C++寫的程序。(參考 *C 和C++)

    部分支持Modula-2和chill,但現在還沒有這方面的文檔。

    調試Pascal程序時,有一些功能還不能使用。

    GDB還可以用來調試FORTRAN程序,盡管現在還不支持表達式的輸入,輸出變量,
    或類FORTRAN的詞法。
    * GDB是"free software",大家都可以免費拷貝。也可以為GDB增加新的功能,不
    過可要遵守GNU的許可協議幺。反正我認為GNU還是比較不錯的:-)
    就這句話:
    Fundamentally, the General Public License is a license which says
    that you have these freedoms and that you cannot take these freedoms
    away from anyone else.
    GDB的作者:
    Richard Stallman是GDB的始作俑者,另外還有許多別的GNU的成員。許多人
    為此作出了貢獻。(都是老外不提也罷,但愿他們不要來找我麻煩:-))

     

    這里是GDB的一個例子:
    原文中是使用一個叫m4的程序。但很遺憾我找不到這個程序的原代碼,
    所以沒有辦法來按照原文來說明。不過反正是個例子,我就拿一個操作系統的
    進程調度原碼來說明把,原代碼我會附在后面。
    首先這個程序叫os.c是一個模擬進程調度的原程序(也許是個老古董了:-))。

    先說明一下如何取得包括原代碼符號的可執行代碼。大家有心的話可以去看一下gcc的

    man文件(在shell下打man gcc)。gcc -g <原文件.c> -o <要生成的文件名>
    -g 的意思是生成帶原代碼調試符號的可執行文件。
    -o 的意思是指定可執行文件名。
    (gcc 的命令行參數有一大堆,有興趣可以自己去看看。)
    (忍不住要加個注,現在應該用gcc -ggdb指定吧!因為有很多人都在問,因為除了gdb
    還有別的工具:-)
    反正在linux下把os.c用以上方法編譯連接以后就產生了可供gdb使用的可執行文件。
    我用gcc -g os.c -o os,產生的可執行文檔叫os.
    然后打gdb os,就可進入gdb,屏幕提示:
    GDB is free software and you are welcome to distribute copies
    of it under certain conditions; type "show copying" to see
    the conditions.
    There is absolutely no warranty for GDB; type "show warranty"
    for details.

    GDB 4.16, Copyright 1995 Free Software Foundation, Inc...
    (gdb)
    (gdb)是提示符,在這提示符下可以輸入命令,直到退出。(退出命令是q/Q)
    為了盡量和原文檔說明的命令相符,即使在本例子中沒用的命令我也將演示。
    首先我們可以設置gdb的屏幕大小。鍵入:
    (gdb)set width 70
    就是把標準屏幕設為70列。
    然后讓我們來設置斷點。設置方法很簡單:break或簡單打b后面加行號或函數名
    比如我們可以在main 函數上設斷點:
    (gdb)break main
    或(gdb)b main
    系統提示:Breakpoint 1 at 0x8049552: file os.c, line 455.
    然后我們可以運行這個程序,當程序運行到main函數時程序就會停止返回到gdb的
    提示符下。運行的命令是run或r(gdb中有不少alias,可以看一下help,在gdb下打help)

    run 后面可以跟參數,就是為程序指定命令行參數。
    比如r abcd,則程序就會abcd以作為參數。(這里要說明的是可以用set args來指定參

    數)。打入r或run后,程序就開始運行直到進入main的入口停止,顯示:
    Starting program: <路徑>/os

    Breakpoint 1, main () at os.c:455
    455 Initial();
    這里455 Initial();是將要執行的命令或函數。
    gdb提供兩種方式:1.單步進入,step into就是跟蹤到函數內啦。命令是step或s
    2.單步,next,就是簡單的單步,不會進入函數。命令是next或n
    這兩個命令還有別的用法以后再說。
    我們用n命令,鍵入:
    (gdb)n
    Success forking process# 1 ,pid is 31474

    Success forking process# 2 ,pid is 31475

    Success forking process# 3 ,pid is 31476

    Success forking process# 4 ,pid is 31477

    Success forking process# 5 ,pid is 31478

    Success forking process# 6 ,pid is 31479

    Dispatching Algorithm : FIFO
    ********************************************************************************


    PCB# PID Priority PC State
    1 31474 24 0 WAITING
    2 31475 19 0 WAITING
    3 31476 16 0 WAITING
    4 31477 23 0 WAITING
    5 31478 22 0 WAITING
    6 31479 20 0 WAITING

    ******************************************************************************


    CPU : NO process running
    IO : No process
    Waiting CPU!!! 31474 31475 31476 31477 31478 31479
    Waiting IO NONE
    456 State=WAITING;
    最后的一行就是下一句要執行的命令。我們現在在另一個函數上加斷點。注意我們
    可以用l/list命令來顯示原代碼。這里我們鍵入
    (gdb)l
    451 main()
    452 {
    453 int message;
    454
    455 Initial();
    456 State=WAITING;
    457 printf("Use Control-C to halt \n");
    458 signal(SIGALRM,AlarmMessage);
    459 signal(SIGINT,InteruptMessage);
    460 signal(SIGUSR2,IoMessage);
    (gdb) l
    461 alarm(TimeSlot);
    462 for(;;)
    463 {
    464 message=GetMessage();
    465 switch(message)
    466 {
    467 case INTERRUPT : printf("Use
    Control-C t;

    468 break;
    469 case CHILD_IO: WaitingIo();
    470 break;
    顯示了原代碼,現在在AlarmMessage上加斷點。
    (gdb) b AlarmMessage
    Breakpoint 2 at 0x8048ee3: file os.c, line 259.
    (gdb)
    然后我們繼續運行程序。
    (gdb)c
    c或continue命令讓我們繼續被中斷的程序。 顯示:
    Continuing.
    Use Control-C to halt

    Breakpoint 2, AlarmMessage () at os.c:259
    259 ClearSignal();
    注意我們下一句語句就是ClearSignal();
    我們用s/step跟蹤進入這個函數看看它是干什么的。
    (gdb) s
    ClearSignal () at os.c:227
    227 signal(SIGINT,SIG_IGN);
    用l命令列出原代碼:
    (gdb) l
    222 }
    223
    224
    225 void ClearSignal() /* Clear other signals */
    226 {
    227 signal(SIGINT,SIG_IGN);
    228 signal(SIGALRM,SIG_IGN);
    229 signal(SIGUSR2,SIG_IGN);
    230 }
    231
    (gdb)
    我們可以用s命令繼續跟蹤。現在讓我們來試試bt或backtrace命令。這個命令可以
    顯示棧中的內容。
    (gdb) bt
    #0 ClearSignal () at os.c:227
    #1 0x8048ee8 in AlarmMessage () at os.c:259
    #2 0xbffffaec in ?? ()
    #3 0x80486ae in ___crt_dummy__ ()
    (gdb)
    大家一定能看懂顯示的意思。棧頂是AlarmMessage,接下來的函數沒有名字--就是
    沒有原代碼符號。這顯示了函數調用的嵌套。
    好了,我們跟蹤了半天還沒有檢查過變量的值呢。檢查表達式的值的命令是p或print
    格式是p <表達式>
    444444讓我們來找一個變量來看看。:-)
    (gdb)l 1
    還記得l的作用嗎?l或list顯示原代碼符號,l或list加<行號>就顯示從<行號>開始的

    原代碼。好了找到一個讓我們來看看WaitingQueue的內容
    (gdb) p WaitingQueue
    = {1, 2, 3, 4, 5, 6, 0}
    (gdb)
    WaitingQueue是一個數組,gdb還支持結構的顯示,
    (gdb) p Pcb
    = {{Pid = 0, State = 0, Prior = 0, pc = 0}, {Pid = 31474, State = 2,
    Prior = 24, pc = 0}, {Pid = 31475, State = 2, Prior = 19, pc = 0}, {
    Pid = 31476, State = 2, Prior = 16, pc = 0}, {Pid = 31477, State = 2,
    Prior = 23, pc = 0}, {Pid = 31478, State = 2, Prior = 22, pc = 0}, {
    Pid = 31479, State = 2, Prior = 20, pc = 0}}
    (gdb)
    這里可以對照原程序看看。
    原文檔里是一個調試過程,不過我想這里我已經把gdb的常用功能介紹了一遍,基本上

    可以用來調試程序了。:-)

    運行GDB(一些詳細的說明):

    前面已經提到過如何運行GDB了,現在讓我們來看一些更有趣的東西。你可以在運行

    GDB時通過許多命令行參數指定大量的參數和選項,通過這個你可以在一開始就設置好

    程序運行的環境。
    這里將要描述的命令行參數覆蓋了大多數的情況,事實上在一定環境下有的并沒有
    什么大用處。最通常的命令就是使用一個參數:
    $gdb <可執行文檔名>
    你還可以同時為你的執行文件指定一個core文件:
    $gdb <可執行文件名> core
    你也可以為你要執行的文件指定一個進程號:
    $gdb <可執行文件名> <進程號> 如:&gdb os 1234將使gdb與進程1234相聯系
    (attach)
    除非你還有一個文件叫1234的。gdb首先檢查一個core文件。
    如果你是使用一個遠程終端進行遠程調試的話,那如果你的終端不支持的話,你將無法

    使用第二個參數甚至沒有core dump。如果你覺得開頭的提示信息比較礙眼的話,你可

    用gdb -silent。你還可以用命令行參數更加詳細的控制GDB的行為。
    打入gdb -help或-h 可以得到這方面的提示。所有的參數都被按照排列的順序傳給gdb

    除非你用了-x參數。
    當gdb開始運行時,它把任何一個不帶選項前綴的參數都當作為一個可執行文件或
    core
    文件(或進程號)。就象在前面加了-se或-c選項。gdb把第一個前面沒有選項說明的參數

    看作前面加了-se 選項,而第二個(如果有的話)看作是跟著-c選項后面的。
    許多選項有縮寫,用gdb -h可以看到。在gdb中你也可以任意的把選項名掐頭去尾,

    要保證gdb能判斷唯一的一個參數就行。
    在這里我們說明一些最常用的參數選項
    -symbols <文件名>(-s <文件名>)------從<文件名>中讀去符號。
    -exec <文件名>(-e <文件名>)----在合適的時候執行<文件名>來做用正確的數據與
    core
    dump的作比較。
    -se <文件名>------從<文件名>中讀取符號并把它作為可執行文件。
    -core <文件名>(-c <文件名>)--指定<文件名>為一個core dump 文件。
    -c <數字>----連接到進程號為<數字>,與attach命令相似。
    -command <文件名>
    -x <文件名>-----執行gdb命令,在<文件名>指定的文件中存放著一序列的gdb命令,就

    象一個批處理。
    -directory(-d) <路徑>---指定路徑。把<路徑>加入到搜索原文件的路徑中。
    -m
    -mapped----
    注意這個命令不是在所有的系統上都能用。如果你可以通過mmap系統調用來獲得內

    映象文件,你可以用這個命令來使gdb把你當前文件里的符號寫入一個文件中,這個文

    將存放在你的當前路徑中。如果你調試的程序叫/temp/fred那么map文件就叫
    ./fred.syms這樣當你以后再調試這個程序時,gdb會認識到這個文件的存在,從而從這

    個文件中讀取符號,而不是從可執行文件中讀取。.syms與主機有關不能共享。
    -r
    -readnow---馬上從符號文件中讀取整個符號表,而不是使用缺省的。缺省的符號表是

    調入一部分符號,當需要時再讀入一部分。這會使開始進入gdb慢一些,但可以加快以

    的調試速度。

    -m和-r一般在一起使用來建立.syms文件


    接下來再談談模式的設置(請聽下回分解 :-))
    附:在gdb文檔里使用的調試例子我找到了在minix下有這個程序,叫m4有興趣的
    可以自己去看看

     

    模式的選擇
    --------------
    現在我們來聊聊gdb運行模式的選擇。我們可以用許多模式來運行gdb,例如在“批模式

    或“安靜模式”。這些模式都是在gdb運行時在命令行作為選項指定的。
    `-nx'
    `-n'
    不執行任何初始化文件中的命令。(一般初始化文件叫做`.gdbinit').一般情況下

    這些文件中的命令會在所有的命令行參數都被傳給gdb后執行。

    `-quiet'
    `-q'
    “安靜模式”。不輸出介紹和版權信息。這些信息在“批模式”中也被跳過。

    `-batch'
    “批模式”。在“批模式”下運行。當在命令文件中的所有命令都被成功的執行

    gdb返回狀態“0”,如果在執行過程中出錯,gdb返回一個非零值。
    “批模式”在把gdb作為一個過濾器運行時很有用。比如在一臺遠程計算機上下載

    執行一個程序。信息“ Program exited normally”(一般是當運行的程序正常結

    時出現)不會在這種模式中出現。
    `-cd DIRECTORY'
    把DIRECTORY作為gdb的工作目錄,而非當前目錄(一般gdb缺省把當前目錄作為工
    作目
    錄)。
    `-fullname'
    `-f'
    GNU Emacs 設置這個選項,當我們在Emacs下,把gdb作為它的一個子進程來運行
    時,
    Emacs告訴gdb按標準輸出完整的文件名和行號,一個可視的棧內容。這個格式跟

    文件名的后面。行號和字符重新按列排,Emacs-to-GDB界面使用2字符作為一個
    顯示一頁原文件的信號。
    `-b BPS'
    為遠程調試設置波特率。

    `-tty DEVICE'
    使用DEVICE來作為你程序的標準輸入輸出

     

    `quit'
    使用'quit'命令來退出gdb,或打一個文件結束符(通常是' CTROL-D')。如果
    你沒有使用表達式,gdb會正常退出,否則它會把表達式的至作為error code
    返回。

    一個中斷(通常是'CTROL-c)不會導致從gdb中退出,而是結束任何一個gdb的命
    令,返回gdb的命令輸入模式。一般在任何時候使用'CTROL-C'是安全的,因為
    gdb會截獲它,只有當安全時,中斷才會起作用。
    如果你正在用gdb控制一個被連接的進程或設備,你可以用'detach'命令來釋放
    它。

    Shell命令
    ==============
    當你偶爾要運行一些shell命令時,你不必退出調試過程,也不需要掛起它;你
    可以使用'shell'命令。

    `shell COMMAND STRING'
    調用標準shell來執行'COMMAND STRING'.環境變量'SHELL'決定了那個shell被
    運行。否則gdb使用'/bin/sh'.
    'make'工具經常在開發環境中使用,所以你可以不用'shell'命令而直接打
    'make'

    `make MAKE-ARGS'
    用指定的命令行變量來運行'make'程序,這等于使用'shell make MAKE-ARGS'
    GDB 命令
    ************
    我們可以把一個gdb命令縮寫成開頭幾個字母,如果這沒有二意性你可以直接回車來

    運行。你還可以使用TAB鍵讓gdb給你完成接下來的鍵入,或向你顯示可選擇的命令

    如果有不止一個選擇的話。

    Command語法
    ==============

    一個gdb命令是一個單行的輸入。長度沒有限制。它一個命令開頭,后面可以跟參
    量。
    比如命令'step'接受一個參量表示單步執行多少步。你也可以不用參量。有的命令

    不接受任何參量。

    gdb命令只要沒有二意性的話就可以被縮寫。另外一些縮寫作為一個命令列出。在某

    情況下二意也是允許的。比如's'是指定'step'的縮寫,但還有命令'start'。你可
    以把
    這些縮寫作為'help'命令的參量來測試它們。
    空行(直接回車)表示重復上一個命令。但有些命令不能重復比如象'run',就不會以

    種方式重復,另外一些當不小心重復會產生嚴重后果的命令也不能用這種方法重
    復。
    'list'和'x'命令當你簡單的打回車時,會建立新的變量,而不是簡單的重復上一個

    令。這樣你可以方便的瀏覽原代碼和內存。
    gdb還有一種解釋RET的方法:分割長輸出。這種方法就和'more'命令相似。由于這
    時經
    常會不小心多打回車,gdb將禁止重復當一個命令產生很長的輸出時。
    任何用'#'開頭一直到行尾的命令行被看作是注釋。主要在命令文件中使用。

    輸入命令的技巧
    ==================
    前面已經提到過TAB鍵的使用。使用TAB鍵能讓你方便的得到所要的命令。比如
    在gdb中:
    (gdb)info bre <TAB>(鍵入info bre,后按TAB鍵)
    gdb能為你完成剩下的輸入。它還能萎蔫提供選擇的可能性。如果有兩個以上可
    能的話,第一次按<TAB>鍵,gdb會響鈴提示,第二次則顯示可能的選擇。同樣gdb
    也可以為一些子命令提供快速的訪問。用法與上相同。
    上例中顯示
    (gdb)info breakepoints
    你也可以直接打回車,gdb就將你輸入的作為命令的可能的縮寫。來判斷執行。
    如果你打入的縮寫不足以判斷,那么gdb會顯示一個列表,列出可能的命令。同樣的
    情況對于命令的參數。在顯示完后gdb把你的輸入拷貝到當前行以便讓你繼續輸入。
    如果你只想看看命令的列表或選項,你可以在命令行下打M-?(就是按著ESC鍵
    同時按SHIFT和?鍵)。你可以直接在命令行下打試試。
    (gdb)<M-?>
    gdb會響鈴并顯示所有的命令。不過這種方式好象在遠程調試是不行。當有的命令
    使用一個字符串時,你可以用" ' "將其括起來。這種方法在調試C++程序時特別有用。

    因為C++支持函數的重載。當你要在某個有重載函數上設斷點時,不得不給出函數參數

    以區分不同的重載函數。這時你就應該把整個函數用" ' "括起來。比如,你要在一個
    叫name的函數上設斷點,而這個函數被重載了(name(int)和name(float))。你將不得
    不給出參變量以區分不同的函數。使用'name(int)'和'name(float)'。這里有個技巧,

    你可以在函數名前加一個" ' "符號。然后打M-?.

    你可以使用help命令來得到gdb的在線幫助。

    `help'
    `h'
    你可以使用help或h后面不加任何參數來得到一個gdb命令類的列表。

    (gdb) help
    List of classes of commands:

    running -- Running the program
    stack -- Examining the stack
    data -- Examining data
    breakpoints -- Making program stop at certain points
    files -- Specifying and examining files
    status -- Status inquiries
    support -- Support facilities
    user-defined -- User-defined commands
    aliases -- Aliases of other commands
    obscure -- Obscure features

    Type "help" followed by a class name for a list of
    commands in that class.
    Type "help" followed by command name for full
    documentation.
    Command name abbreviations are allowed if unambiguous.
    (gdb)

    `help CLASS'
    使用上面列出的help class作為help或h的參量,你可以得到單一的命令列表。
    例如顯示一個'status'類的列表。

    (gdb) help status
    Status inquiries.

    List of commands:

    show -- Generic command for showing things set
    with "set"
    info -- Generic command for printing status

    Type "help" followed by command name for full
    documentation.
    Command name abbreviations are allowed if unambiguous.
    (gdb)

    `help COMMAND'
    詳細列出單個命令的資料。

    `complete ARGS'
    列出所有以ARGS開頭的命令。例如:

    complete i

    results in:

    info
    inspect
    ignore

    This is intended for use by GNU Emacs.

    除了使用'help'你還可以使用gdb的命令'info'和'show'來查詢你程序的
    狀態,每個命令可以查詢一系列的狀態。這些命令以恰當的方式顯示所有的
    子命令。

    `info'
    此命令(可以縮寫為'i')用來顯示你程序的狀態。比如,你可以使用info
    args 列出你程序所接受的命令行參數。使用info registers列出寄存器的狀態。
    或用info breakpoint列出在程序中設的斷點。要獲得詳細的關于info的信息打
    help info.
    `set'
    這個命令用來為你的程序設置一個運行環境(使用一個表達式)。比如你
    可以用set prompt $來把gdb的提示符設為$.

    `show'
    與'info'相反,'show'命令用來顯示gdb自身的狀態。你使用'set'命令來
    可以改變絕大多數由'show'顯示的信息。比如使用show radix命令來顯示基數。
    用不帶任何參變量的'set'命令你可以顯示所有你可以設置的變量的值。
    有三個變量是不可以用'set'命令來設置的。
    `show version'
    顯示gdb的版本號。如果你發現gdb有bug的話你應該在bug-reports里加
    入gdb的版本號。

    `show copying'
    顯示版權信息。

    `show warranty'
    顯示擔保信息。
    在gdb下運行你的程序
    **************************
    當你在gdb下運行程序時,你必須先為gdb準備好帶有調試信息的可執行文檔。
    還可以在gdb中為你的程序設置參變量,重定向你程序的輸入/輸出,設置環境變
    量,調試一個已經執行的程序或kill掉一個子進程。
    這里許多內容在早先的例子中都已經用到過,可以參見gdb(二)。
    目錄:

    * 編譯:: 為調試編譯帶調試信息的代碼
    * 運行:: 運行你的程序
    * 參變量:: 為你的程序設置參變量
    * 運行環境:: 為你的程序設置運行時環境
    * 設置工作目錄:: 在gdb中設置程序的工作目錄。
    * 輸入/輸出:: 設定你程序的輸入和輸出
    * 連接:: 調試一個已經運行的程序
    * 結束子進程:: Kill子進程
    * 進程信息:: 附加的進程信息
    * 線程:: 調試帶多線程的程序
    * 多進程:: 調試帶多進程的程序
    為調試準備帶調試信息的代碼
    ===========================
    為了高效的調試一個程序,你需要使用編譯器來產生附帶調試信息的可執行代碼
    這些調試信息存儲在目標文件中;描述了變量數據類型和函數聲明,在原文件代碼行
    和執行代碼之間建立聯系。
    為產生調試信息,當你使用編譯器時指定'-g'選項,就可以為你的程序產生帶有
    調試信息的可執行代碼。
    有些c編譯器不支持'-g'選項和'-O'選項,那你就有麻煩了,或者有別的方法產生
    帶調試信息的可執行代碼,要不就沒辦法了。
    gcc,GNU的c語言編譯器支持'-g'和'-O'選項。這樣你就可以產生帶調試信息的且
    優化過的可執行代碼.
    當你使用gdb來調試一個使用'-g','-O'選項產生的程序時,千萬記住編譯器為了優

    化你的程序重新安排了你的程序。不要為運行次序與你原來設想的不同,最簡單的例子

    就是當你定義了一個變量但從未使用過它時,gdb中是看不到這個變量的--因為它已經

    被優化掉了。
    所以有時你不要使用'-O'選項,如果當你不用優化時產生的程序是正確的,而優化

    過后變的不正確了,那么這是編譯器的bug你可以向開發者提供bug-reports(包括出錯

    的例子)。
    早期的GUN C語言編譯器允許'-gg'選項,也用來產生調試信息,gdb不再支持這種格

    式的調試信息,如果你的編譯器支持'-gg'選項,請不要使用它。

    `run'
    `r'
    使用'run'命令在gdb下啟動你的程序。你必須先指定你程序的名字(用gdb的命令

    參數)或使用'file'命令,來指定文件名。如果你在一個支持多進程的環境下運行你的

    序'run'命令創建一個子進程然后加載你的程序。如果環境不支持進程,則gdb直接調到

    程序的第一條命令。
    一些父進程設置的參量可以決定程序的運行。gdb提供了指定參量的途徑,但你必須

    在程序執行前設置好他們。你也可以在運行過程中改變它們,但每次改變只有在下一次

    運行中才會體現出來。這些參量可以分為四類:
    ---參數
    你可以在使用'run'命令時設置,如果shell支持的話,你還可以使用通配符,或

    變量代換。在UNIX系統中你可以使用'shell環境變量'來控制shell。
    ---環境:
    你的程序一般直接從gdb那里繼承環境變量。但是你可以使用'set environment'

    命令來設置專門的環境變量。
    ---工作目錄
    你的程序還同時從gdb那里繼承了工作目錄,你可以使用'cd'命令在gdb中改變工作

    目錄。
    ---標準輸入/輸出
    你的程序一般使用與gdb所用的相似的設備來輸入/輸出。不過你可以為你的程序

    輸入/輸出進行重定向。使用'run'或'tty'命令來設置于gdb所用不同的設備。
    *注意:當你使用輸入/輸出重定向時,你將不能使用無名管道來把你所調試的程序的輸

    傳給另一個程序。這樣gdb會認為調試程序出錯。
    當你發出'run'命令后,你的程序就開始運行。
    如果你的符號文件的時間與gdb上一次讀入的不同,gdb會廢棄原來的符號表并重新

    入。當前的斷點不變。

     

    程序環境
    ==========================
    “環境”包括了一系列的環境變量和它們的值。環境變量一般記錄了一些常用的信
    息,
    比如你的用戶名,主目錄,你的終端型號和你的運行程序的搜索路徑。一般你可以在
    shell
    下設置環境變量,然后這些變量被所有你所運行的程序所共享。在調試中,可以設置恰

    的環境變量而不用退出gdb.

    `path DIRECTORY'
    在'PATH'環境變量前加入新的內容('PATH'提供了搜索執行文件的路徑)。對于gdb

    你的程序來說你也許要設置一些專門的路徑。使用':'或空格來分隔。如果DIRECTORY已

    在路徑中了,這個操作將會把它移到前面。
    你可以使用串'$cmd'來代表當前路徑,如果你用'.'的話,它代表你使用'path'命

    時的路徑,gdb將在把DIRECTORY加入搜索路徑前用'.'代替當前路徑

    `show paths'
    顯示當前路徑變量的設置情況。

    `show environment [VARNAME]'
    顯示某個環境變量的值。如果你不指明變量名,則gdb會顯示所有的變量名和它們

    內容。environment可以被縮寫成'env'

    `set environment VARNAME [=] VALUE'
    設置某個環境變量的值。不過只對你所調試的程序有效。對gdb本身是不起作用
    的。
    值可以是任何串。如果未指定值,則該變量值將被設為NULL.
    看一個例子:
    set env USER = foo
    告訴一個linux程序,當它下一次運行是用戶名將是'foo'

    `unset environment VARNAME'
    刪除某環境變量。

    注意:gdb使用'shell'環境變量所指定的shell來運行你的程序。

     

    工作路徑
    ================================
    當你每次用'run'命令來運行你的程序時,你的程序將繼承gdb的
    當前工作目錄。而gdb的工作目錄是從它的父進程繼承而來的(一般是
    shell)。但你可以自己使用'cd'命令指定工作目錄。
    gdb的工作目錄就是它去尋找某些文件或信息的途徑。
    `cd DIRECTORY'
    把gdb的工作目錄設為DIRECTORY
    `pwd'
    打印輸出當前目錄。
    你程序的輸入/輸出
    ===============================
    缺省時,你的程序的輸入/輸出和gdb的輸入/輸出使用同一個終端。
    gdb在它自己和你的程序之間切換來和你交互,但這會引起混亂。
    `info terminal'
    顯示你當前所使用的終端的類型信息。
    你可以把你程序的輸入/輸出重定向。
    例如:
    run > outfile
    運行你的程序并把你程序的標準輸出寫入文件outfile中。
    另一個為你程序指定輸入/輸出的方法是使用'tty'命令,這個命令
    接受一個文件名作為參量把這個文件作為以后使用'run'命令的缺省命
    令文件。它還重新為子進程設置控制終端。
    例如:
    tty /dev/ttyb
    指定以后用'run'命令啟動的進程使用終端'/dev/ttyb'作為程序的輸入
    /輸出,而且把這個終端設為你進程的控制終端。
    一個清楚的使用'run'命令的重定向將重新設置'tty'所設置的內容
    ,但不影響控制終端。 當你使用'tty'命令或在'run'命令中對輸入
    /輸出進行重定向時,只有你當前調試的程序的輸入/輸出被改變了,
    并不會影響到別的程序。
    調試一個已經運行的程序:
    ====================================

    `attach PROCESS-ID'
    這個命令把一個已經運行的進程(在gdb外啟動)連接入gdb,以便
    調試。PROCESS-ID是進程號。(UNIX中使用'ps'或'jobs -l'來查看進程)
    'attach'一般不重復。(當你打了一個以上的回車時)
    當然要使用'attach'命令的話,你的操作系統環境必須支持進程。
    另外你還要有向此進程發信號的權力。
    當使用'attach'命令時,你應該先使用'file'命令來指定進程所
    聯系的程序源代碼和符號表。 當gdb接到'attach'命令后第一件
    事就是停止進程的運行,你可以使用所有gdb的命令來調試一個“連接”
    的進程,就象你用'run'命令在gdb中啟動它一樣。如果你要進程繼續運
    行,使用'continue'或'c'命令就行了。
    `detach'
    當你結束調試后可以使用此命令來斷開進程和gdb的連接。(解除gdb
    對它的控制)在這個命令執行后進程將繼續執行。
    如果你在用'attach'連接一個進程后退出了gdb,或使用'run'命令執
    行了另一個進程,這個被'attach'的進程將被kill掉。但缺省時,gdb會
    要求你確認你是否要退出或執行一個新的進程。

     

    結束子進程
    =========================
    `kill'
    Kill命令結束你程序在gdb下開的子進程
    這個命令當你想要調試(檢查)一個core dump文件時更有用。gdb在調試過程中
    會忽略所有的core dump。
    在一些操作系統上,一個程序當你在上面加了斷點以后就不能離開gdb獨立運行。
    你可以用kill命令來解決這個問題。
    'kill'命令當你想重新編譯和連接你的程序時也很有用。因為有些系統不允許修改

    正在執行的可執行程序。這樣當你再一次使用'run'命令時gdb會知道你的程序已經被改

    變了,那么gdb會重新load新的符號。(而且盡量保持你當前的斷點設置。
    附加的進程信息
    ==============================
    一些操作系統提供了一個設備目錄叫做'/proc'的,供檢查進程映象。如果gdb被在

    樣的操作系統下運行,你可以使用命令'info proc'來查詢進程的信息。('info proc'

    令只在支持'procfs'的SVR4系統上有用。
    `info proc'
    顯示進程的概要信息。
    `info proc mappings'
    報告你進程所能訪問的地址范圍。
    `info proc times'
    你進程和子進程的開始時間,用戶時間(user CPU time),和系統CPU時間。
    `info proc id'
    報告有關進程id的信息。
    `info proc status'
    報告你進程的一般狀態信息。如果進程停止了。這個報告還包括停止的原因和收
    到的
    信號。
    `info proc all'
    顯示上面這些命令返回的所有信息。
    對多線程程序的調試
    ========================================
    一些操作系統中,一個單獨的程序可以有一個以上的線程在運行。線程和進程精確
    的定?
    ?

    ?
    ?
    有自己的寄存器,運行時堆棧或許還會有私有內存。
    gdb提供了以下供調試多線程的進程的功能:
    * 自動通告新線程。
    * 'thread THREADNO',一個用來在線程之間切換的命令。
    * 'info threads',一個用來查詢現存線程的命令。
    * 'thread apply [THREADNO] [ALL] ARGS',一個用來向線程提供命令的命令。
    * 線程有關的斷點設置。
    注意:這些特性不是在所有gdb版本都能使用,歸根結底要看操作系統是否支持。
    如果你的gdb不支持這些命令,會顯示出錯信息:
    (gdb) info threads
    (gdb) thread 1
    Thread ID 1 not known. Use the "info threads" command to
    see the IDs of currently known threads.
    gdb的線程級調試功能允許你觀察你程序運行中所有的線程,但無論什么時候
    gdb控制,總有一個“當前”線程。調試命令對“當前”進程起作用。
    一旦gdb發現了你程序中的一個新的線程,它會自動顯示有關此線程的系統信
    息。比如:
    [New process 35 thread 27]
    不過格式和操作系統有關。
    為了調試的目的,gdb自己設置線程號。
    `info threads'
    顯示進程中所有的線程的概要信息。gdb按順序顯示:
    1.線程號(gdb設置)
    2.目標系統的線程標識。
    3.此線程的當前堆棧。
    一前面打'*'的線程表示是當前線程。
    例如:
    (gdb) info threads
    3 process 35 thread 27 0x34e5 in sigpause ()
    2 process 35 thread 23 0x34e5 in sigpause ()
    * 1 process 35 thread 13 main (argc=1, argv=0x7ffffff8)
    at threadtest.c:68

     

    `thread THREADNO'
    把線程號為THREADNO的線程設為當前線程。命令行參數THREADNO是gdb內定的
    線程號。你可以用'info threads'命令來查看gdb內設置的線程號。gdb顯示該線程
    的系統定義的標識號和線程對應的堆棧。比如:

    (gdb) thread 2
    [Switching to process 35 thread 23]
    0x34e5 in sigpause ()
    "Switching后的內容取決于你的操作系統對線程標識的定義。

    `thread apply [THREADNO] [ALL] ARGS'
    此命令讓你對一個以上的線程發出相同的命令"ARGS",[THREADNO]的含義同上。
    如果你要向你進程中的所有的線程發出命令使用[ALL]選項。
    無論gdb何時中斷了你的程序(因為一個斷點或是一個信號),它自動選擇信號或
    斷點發生的線程為當前線程。gdb將用一個格式為'[Switching to SYSTAG]'的消息
    來向你報告。
    *參見:運行和停止多線程程序。
    *參見:設置觀察點

    調試多進程的程序
    ==========================================
    gdb對調試使用'fork'系統調用產生新進程的程序沒有很多支持。當一個程序開始
    一個新進程時,gdb將繼續對父進程進行調試,子進程將不受影響的運行。如果你在子

    進程可能會執行到的地方設了斷點,那么子進程將收到'SIGTRAP'信號,如果子進程沒

    有對這個信號進行處理的話那么缺省的處理就是使子進程終止。
    然而,如果你要一定要調試子進程的話,這兒有一個不是很麻煩的折衷的辦法。在

    子進程被運行起來的開頭幾句語句前加上一個'sleep'命令。這在調試過程中并不會引

    起程序中很大的麻煩(不過你要自己注意例外的情況幺:-))。然后再使用'ps'命令列出

    新開的子進程號,最后使用'attach'命令。這樣就沒有問題了。
    關于這一段,本人覺得實際使用上并不全是這樣。我在調試程中就試過,好象不一定

    能起作用,要看gdb的版本和你所使用的操作系統了。

     

    停止和繼續
    ***********************
    調試器的基本功能就是讓你能夠在程序運行時在終止之前在某些條件下停止下來,

    后再繼續運行,這樣的話你就可以檢查當你的程序出錯時你的程序究竟做了些什么。
    在gdb內部,你的程序會由于各種原因而暫時停止,比如一個信號,一個斷點,或是

    由于你用了'step'命令。在程序停止的時候你就可以檢查和改變變量的值,設置或去掉

    斷點,然后繼續你程序的運行。一般當程序停下來時gdb都會顯示一些有關程序狀態的

    息。比如象程序停止的原因,堆棧等等。如果你要了解更詳細的信息,你可以使用
    'info
    program'命令。另外,在任何時候你輸入這條命令,gdb都會顯示當前程序運行的狀態

    息。

    `info program'
    顯示有關你程序狀態的信息:你的程序是在運行還是停止,是什么進程,為什么

    止。

    斷點,觀察點和異常
    ========================================
    斷點的作用是當你程序運行到斷點時,無論它在做什么都會被停止下來。對于每個
    斷點
    你都可以設置一些更高級的信息以決定斷點在什么時候起作用。你可以使用'break’命

    來在你的程序中設置斷點,在前面的例子中我們已經提到過一些這個命令的使用方法
    了。
    你可以在行上,函數上,甚至在確切的地址上設置斷點。在含有異常處理的語言(比如

    c++)中,你還可以在異常發生的地方設置斷點。
    在SunOS 4.x,SVR4和Alpha OSF/1的設置中,你還可以在共享庫中設置斷點。
    觀察點是一種特殊的斷點。它們在你程序中某個表達式的值發生變化時起作用。你

    須使用另外一些命令來設置觀察點。除了這個特性以外,你可以象對普通斷點一樣對觀

    點進行操作--使用和普通斷點操作一樣的命令來對觀察點使能,使不能,刪除。
    你可以安排當你程序被中斷時顯示的程序變量。
    當你在程序中設置斷點或觀察點時gdb為每個斷點或觀察點賦一個數值.在許多對斷

    操作的命令中都要使用這個數值。

     

    設置斷點
    =============
    使用'break'或簡寫成'b'來設置斷點。gdb使用環境變量$bpnum來記錄你最新設置的

    斷點。
    你有不少方法來設置斷點。


    `break FUNCTION'
    此命令用來在某個函數上設置斷點。當你使用允許函數重載的語言比如C++時,有

    能同時在幾個重載的函數上設置了斷點。

    `break +OFFSET'
    `break -OFFSET'
    在當前程序運行到的前幾行或后幾行設置斷點。OFFSET為行號。

    `break LINENUM'
    在行號為LINENUM的行上設置斷點。程序在運行到此行之前停止。

    `break FILENAME:LINENUM'
    在文件名為FILENAME的原文件的第LINENUM行設置斷點。

    `break FILENAME:FUNCTION'
    在文件名為FILENAME的原文件的名為FUNCTION的函數上設置斷點。
    當你的多個文件中可能含有相同的函數名時必須給出文件名。

    `break *ADDRESS'
    在地址ADDRESS上設置斷點,這個命令允許你在沒有調試信息的程
    序中設置斷點。
    `break'
    當'break'命令不包含任何參數時,'break'命令在當前執行到的程
    序運行棧中的下一條指令上設置一個斷點。除了棧底以外,這個命令使
    程序在一旦從當前函數返回時停止。相似的命令是'finish',但'finish'
    并不設置斷點。這一點在循環語句中很有用。
    gdb在恢復執行時,至少執行一條指令。

    `break ... if COND'
    這個命令設置一個條件斷點,條件由COND指定;在gdb每次執行到此
    斷點時COND都被計算當COND的值為非零時,程序在斷點處停止。這意味著
    COND的值為真時程序停止。...可以為下面所說的一些參量。

    `tbreak ARGS'
    設置斷點為只有效一次。ARGS的使用同'break'中的參量的使用。

    `hbreak ARGS'
    設置一個由硬件支持的斷點。ARGS同'break'命令,設置方法也和
    'break'相同。但這種斷點需要由硬件支持,所以不是所有的系統上這個
    命令都有效。這個命令的主要目的是用于對EPROM/ROM程序的調試。因為
    這條命令可以在不改變代碼的情況下設置斷點。這可以同SPARCLite DSU
    一起使用。當程序訪問某些變量和代碼時,DSU將設置“陷井”。注意:
    你只能一次使用一個斷點,在新設置斷點時,先刪除原斷點。
    thbreak ARGS'
    設置只有一次作用的硬件支持斷點。ARGS用法同'hbreak'命令。這個命令
    和'tbreak'命令相似,它所設置的斷點只起一次作用,然后就被自動的刪除。這
    個命令所設置的斷點需要有硬件支持。
    `rbreak REGEX'
    在所有滿足表達式REGEX的函數上設置斷點。這個命令在所有相匹配的函數
    上設置無條件斷點,當這個命令完成時顯示所有被設置的斷點信息。這個命令設
    置的斷點和'break'命令設置的沒有什么不同。這樣你可以象操作一般的斷點一
    樣對這個命令設置的斷點進行刪除,使能,使不能等操作。當調試C++程序時這
    個命令在重載函數上設置斷點時非常有用。

    `info breakpoints [N]'
    `info break [N]'
    `info watchpoints [N]'
    顯示所有的斷點和觀察點的設置表,有下列一些列

    *Breakpoint Numbers*----斷點號
    *Type*----斷點類型(斷點或是觀察點)
    *Disposition*---顯示斷點的狀態。

    *Enabled or Disabled*---使能或不使能。'y'表示使能,'n'表示不使能。

    *Address*----地址,斷點在你程序中的地址(內存地址)
    *What*---地址,斷點在你程序中的行號。
    如果斷點是條件斷點,此命令還顯示斷點所需要的條件。
    帶參數N的'info break'命令只顯示由N指定的斷點的信息。
    此命令還顯示斷點的運行信息(被執行過幾次),這個功能在使用'ignore'
    命令時很有用。你可以'ignore'一個斷點許多次。使用這個命令可以查看斷點
    被執行了多少次。這樣可以更快的找到錯誤。
    gdb允許你在一個地方設置多個斷點。但設置相同的斷點無疑是弱智的。不過
    你可以使用條件斷點,這樣就非常有用。
    gdb有時會自動在你的程序中加入斷點。這主要是gdb自己的需要。比如為了正
    確的處理C語言中的'longjmp'。這些內部斷點都是負值,以'-1'開始。'info
    breakpoints'不會顯示它們。
    不過你可以使用命令’maint info breakpoints'來查看這些斷點。

    `maint info breakpoints'
    使用格式和'info breakpoints'相同,顯示所有的斷點,無論是你設置的還是
    gdb自動設置的。
    以下列的含義:

    `breakpoint'
    斷點,普通斷點。
    `watchpoint'
    普通觀察點。

    `longjmp'
    內部斷點,用于處理'longjmp'調用。

    `longjmp resume'
    內部斷點,設置在'longjmp'調用的目標上。

    `until'
    'until'命令所使用的內部斷點。

    `finish'
    'finish'命令所使用的內部斷點。

     

    設置觀察點
    ==============
    你可以使用觀察點來停止一個程序,當某個表達式的值改變時,觀察點會將程序
    停止。而不需要先指定在某個地方設置一個斷點。
    由于觀察點的這個特性,使觀察點的使用時開銷比較大,但在捕捉錯誤時非常有
    用。特別是你不知道你的程序什么地方出了問題時。

    `watch EXPR'
    這個命令使用EXPR作為表達式設置一個觀察點。GDB將把表達式加入到程序中
    并監視程序的運行,當表達式的值被改變時GDB就使程序停止。這個也可以被用在
    SPARClite DSU提供的新的自陷工具中。當程序存取某個地址或某條指令時(這個地
    址在調試寄存器中指定),DSU將產生自陷。對于數據地址DSU支持'watch'命令,然而
    硬件斷點寄存器只能存儲兩個斷點地址,而且斷點的類型必須相同。就是兩個
    'rwatch'型斷點,或是兩個'awatch'型斷點。

    `rwatch EXPR'
    設置一個觀察點,當EXPR被程序讀時,程序被暫停。

    `awatch EXPR'
    設置一個觀察點,當EXPR被讀出然后被寫入時程序被暫停。這個命令和'awatch'
    命令合用。

    `info watchpoints'
    顯示所設置的觀察點的列表,和'info break'命令相似。
    *注意:*在多線程的程序中,觀察點的作用很有限,GDB只能觀察在一個線程中
    的表達式的值如果你確信表達式只被當前線程所存取,那么使用觀察點才有效。GDB
    不能注意一個非當前線程對表達式值的改變。

    斷點和異常
    ==============
    在一些語言中比如象GNU C++,實現了異常處理。你可以使用GDB來檢查異常發生的

    原因。而且GDB還可以列出在某個點上異常處理的所有過程。

    `catch EXCEPTIONS'
    你可以使用這個命令來在一個被激活的異常處理句柄中設置斷點。EXCEPTIONS是

    一個你要抓住的異常。
    你一樣可以使用'info catch'命令來列出活躍的異常處理句柄。
    現在GDB中對于異常處理由以下情況不能處理。
    * 如果你使用一個交互的函數,當函數運行結束時,GDB將象普通情況一樣把控制返

    回給你。如果在調用中發生了異常,這個函數將繼續運行直到遇到一個斷點,一個信號

    或是退出運行。
    * 你不能手工產生一個異常( 即異常只能由程序運行中產生 )
    * 你不能手工設置一個異常處理句柄。
    有時'catch'命令不一定是調試異常處理的最好的方法。如果你需要知道異常產生的

    確切位置,最好在異常處理句柄被調用以前設置一個斷點,這樣你可以檢查棧的內容。

    如果你在一個異常處理句柄上設置斷點,那么你就不容易知道異常發生的位置和原因。

    要僅僅只在異常處理句柄被喚醒之前設置斷點,你必須了解一些語言的實現細節。

    比如在GNU C++中異常被一個叫'__raise_exception'的庫函數所調用。這個函數的原
    型是:

    /* ADDR is where the exception identifier is stored.
    ID is the exception identifier. */
    void __raise_exception (void **ADDR, void *ID);
    要使GDB在棧展開之前抓住所有的句柄,你可以在函數'__raise_exception'上設置斷
    點。
    對于一個條件斷點,由于它取決于ID的值,你可以在你程序中設置斷點,當某個特

    別的異常被喚醒。當有一系列異常被喚醒時,你可以使用多重條件斷點來停止你的程
    序。

     

    刪除斷點
    ===================
    很自然當一個斷點或是一個觀察點完成了它的使命后,你需要把它從程序中刪去。

    不然你的程序還會在相同的地方停主,給你造成干擾。使用'clear'命令來從程序中刪

    一個斷點。
    使用'clear'命令你可以刪除指定位置的斷點。使用'delete'命令你可以使用斷點號

    來指定要刪去的斷點或觀察點。
    在刪除斷點時不需要先運行過它,GDB會忽略你剛才刪去的斷點。所以你可以繼續運

    你的程序而不必管斷點。

    `clear'
    在當前選擇的棧幀上清除下一個所要執行到的斷點(指令級)。當你當前選擇幀是
    棧中
    最內層時使用這個命令可以很方便的刪去剛才程序停止處的斷點。

    `clear FUNCTION'
    `clear FILENAME:FUNCTION'
    刪除名為FUNCITON的函數上的斷點。

    `clear LINENUM'
    `clear FILENAME:LINENUM'
    刪除以LINENUM為行號上的斷點。

    `delete [breakpoints] [BNUMS...]'
    刪除參數所指定的斷點,如果沒有指定參數則刪去程序中所有的斷點。這個命令
    可以
    縮寫成為'd'

    使斷點暫時不起作用。
    ========================
    如果你只是想讓斷點一時失去作用以方便調試的話,你可以先使斷點不起作用。
    當你以后又想使用時可以用'enable'命令激活它們。
    你使用'enable'命令來激活斷點或是觀察點,使用'disable'命令來使斷點或觀察點

    不起作用。使用'info break'或'info watch'來查看那些斷點是活躍的。
    斷點或觀察點有四種狀態:
    * 使能。當程序運行到斷點處時,程序停止。使用'break'命令設置的斷點一開始缺

    是使能的。
    *不使能。斷點對你程序的運行沒有什么影響。
    *使能一次后變為不使能。斷點對你的程序運行只有一次影響,然后就自動變成不使

    狀態。使用'tbreak'設置的斷點一開始缺省是這個狀態。
    * 使能一次自動刪除。斷點在起了一次作用后自動被刪除。
    你可以使用以下的命令來使能或使不能一個斷點或觀察點。

    `disable [breakpoints] [BNUMS...]'
    使由參數指定的斷點或觀察點變為不使能,如果沒有參數的話缺省使所有斷點和
    觀察
    點變為不使能。當一個斷點或觀察點被不使能后在被不使能前的狀態被記錄下來,在斷
    點或
    觀察點再次被激活時,原來的狀態得到繼續。比如一個條件斷點或一個設置了
    'ignore-counts'的斷點在被使不能后記錄活躍時斷點被執行的次數,在不使能狀態下
    ,斷
    點的執行次數(ignore-counts)不增加,直到斷點再次被激活時,再繼續計算條件
    (ignore-counts)。你可以使用'disable'命令的縮寫'dis'

    `enable [breakpoints] [BNUMS...]'
    使能由參數指定的斷點或全部斷點。

    `enable [breakpoints] once BNUMS...'
    功能同上條命令,只是這條命令使斷點只使能一次。

    `enable [breakpoints] delete BNUMS...'
    功能同上條命令,只是這條命令使被使能的斷點起作用一次然后自動被刪除。
    除了使用'tbreak'命令所設置的斷點以外,斷點被設置時都是使能的。

     

    斷點條件
    ===========
    最簡單的斷點就是當你的程序每次執行到的時候就簡單將程序掛起。你也可以為斷

    設置“條件”。條件只是你所使用的編程語言的一個布爾表達式,帶有條件表達式的斷

    在每次執行時判斷計算表達式的值,當表達式值為真時才掛起程序。
    這是使用“斷言”的一中形式,在這種形式中你只有在斷言為真時才掛起程序。如

    在C語言中你要使斷言為假時掛起程序則使用:“!表達式”。
    條件表達式對觀察點也同樣有效,但你并不需要它,因為觀察點本身就計算一個表
    達式?
    ?
    但它也許會簡單一些。比如只在一個變量名上設置觀察點然后設置一個條件來測試新的

    值。
    斷點條件可能有副作用(side effects)會影響程序的運行。這一點有時也是很有用的

    比如來激活一個顯示程序完成情況的的函數,或使用你自己的打印函數來格式化特殊的

    數據結構。當在同一位置沒有另一個斷點設置時,結果是可預見的。(在gdb中如果在同

    個地方使用了一個斷點和一個條件斷點則普通斷點可能先被激活。)在條件斷點的應用

    有很多技巧。
    斷點條件可以在設置斷點的同時被設置。使用'if'命令作為'break'命令的參數。斷

    條件也可以在任何時候使用'condition'命令來設置。'watch'命令不能以'if'作為參數


    所以使用'condition'命令是在觀察點上設置條件的唯一方法。

    `condition BNUM EXPRESSION'
    把'EXPRESSIN'作為斷點條件。斷點用'BNUM'來指定。在你為BNUM號斷點設置了條

    后,只有在條件為真時程序才被暫停。當你使用'condition'命令GDB馬上同步的檢查
    'EXPRESSION'的值判斷表達式中的符號在斷點處是否有效,但GDB并不真正計算表達式

    的值。

    `condition BNUM'
    刪除在'BNUM'號斷點處的條件。使之成為一個普通斷點。
    一個條件斷點的特殊例子是時一個程序在執行了某句語句若干次后停止。由于這
    個功能非常常用,你可以使用一個命令來直接設置它那就是'ignore count'。每個
    斷點都有'ignore count',缺省是零。如果'ignore count'是正的那么你的程序在
    運行過斷點處'count'次后被暫停。

    `ignore BNUM COUNT'
    設置第BNUM號斷點的'ignore count'為'COUNT'。
    如果要讓斷點在下次執行到時就暫停程序,那么把'COUNT'設為0.
    當你使用'continue'命令來繼續你程序的執行時,你可以直接把'ignore count'

    作為'continue'的參數使用。你只要直接在'continue'命令后直接跟要"ignore"的
    次數就行。
    如果一個斷點同時有一個ignore count和一個條件時,條件不被檢查。只有當
    'ignore count'為零時GDB才開始檢查條件的真假。
    另外你可以用'condition'命令來獲得與用‘ignore count'同樣效果的斷點。用

    是用類似于'$foo--<=0'的參量作為'condition'命令的參數(使用一個不停減量的變量

    作為條件表達式的成員)。

     

    斷點命令列表
    ==================
    你可以為任一個斷點或觀察點指定一系列命令,當你程序執行到斷點時,GDB自動執

    這些命令。例如:你可以打印一些表達式的值,或使能其他的斷點。

    `commands [BNUM]'
    `... COMMAND-LIST ...'
    `end'
    為斷點號為BNUM的斷點設置一個命令列表。這些命令在'...COMMAND-LIST...'中

    出使用'end'命令來表示列表的結束。
    要刪除斷點上設置的命令序列,你只需在'command'命令后直接跟'end'命令就可以

    了。
    當不指定BNUM時,GDB缺省為最近遇到的斷點或是觀察點設置命令列表。
    使用回車來表示重復使用命令的特性在'...command list...'中不能使用。
    你可以使用命令列表中的命令來再次使你的程序進入運行狀態。簡單的在命令列表

    中使用'continue'命令,或'step'命令。
    在使程序恢復執行的命令后的命令都被忽略。這是因為一旦你的程序重新運行就可

    能遇到新的命令列表,那么就應該執行新的命令。防止了二義。
    如果你在命令列表中使用了'silent'命令,那么你程序在斷點處停止的信息將不被

    顯示。這對于用一個斷點然后顯示一些信息,接著再繼續執行很有用。但'silent'命令

    只有在命令列表的開頭有效。
    命令'echo','output'和'printf'允許你精確的控制顯示信息,這些命令在
    "silent"
    斷點中很有用。
    例如:這個例子演示了使用斷點命令列表來打印'x'的值.

    break foo if x>0
    commands
    silent
    printf "x is %d\n",x
    cont
    end
    斷點命令列表的一個應用是在遇到一個buf之后改正數據然后繼續調試的過程。
    使用命令來修改含有錯誤值的變量,然后使用'continue'命令繼續程序的運行。
    使用'silent'命令屏蔽輸出:

    break 403
    commands
    silent
    set x = y + 4
    cont
    end

     

    斷點菜單
    ==============
    一些編程語言(比如象C++)允許一個函數名被多次使用(重載),以方便應用的使用。

    當一個函數名被重載時,'break FUNCITON'命令向GDB提供的信息不夠GDB了解你要設置

    斷點的確切位置。如果你了解到這個問題,你可以使用'break FUNCITONS(TYPES)'命令

    來指定斷點的確切位置。否則GDB會提供一個函數的選擇的菜單供你選擇。使用提示符

    '>'來等待你的輸入。開始的兩個選擇一般是'[0] cancel'和'[1] all'輸入1則在所有

    同名函數上加入斷點。輸入0則退出選擇。
    下例為企圖在重載的函數符號'String::after'上設置斷點。
    (gdb) b String::after
    [0] cancel
    [1] all
    [2] file:String.cc; line number:867
    [3] file:String.cc; line number:860
    [4] file:String.cc; line number:875
    [5] file:String. 

     

    posted @ 2005-08-03 15:51 李嵐 閱讀(1517) | 評論 (0)編輯 收藏


    2005年6月1日

    理解AOP

    我覺得面向對象很好地解決了軟件系統中職責劃分的問題.借助于面向對象,軟件開發人員一般的,都可以將需求里的名詞轉換成系統中的對象,動詞轉換為對象里的方法.這樣非常符合人的思維方式,非常自然.


    但是,問題是某些需求卻偏偏不是能用這樣的”名詞”和”動詞”就能完美的描述出來的,假如這樣的問題:需要對系統中的某些方法進行事務處理,這種需要事務代碼散布在多個類中.面對這種需求,應該怎么辦呢?最直接的辦法就是:創建一個基類(接口)或者一個助手,將事務處理的功能放在其中,并讓所有需要事務功能的類繼承這個基類(接口)或者使用這個助手.加入這樣的.需要修改的地方就會分散在多個文件中.這樣大的修改量,無疑會增加出錯的幾率,并且加大系統維護的難度,如圖:

                                          1.jpg




    因此,面向方面的編程(
    Aspect Oriented Programming,AOP)應運而生.AOP為開發者提供了一種描述橫切關注點的機制,并能夠自動將橫切關注點織入到面向對象的軟件系統中,從而實現了橫切關注點的模塊化.通過劃分Aspect代碼,橫切關注點變得容易處理.開發者可以在編譯時更改,插入或除去系統的Aspect,甚至重用系統的Aspect.” OOP只用于表示對象之間的泛化-特化(generalization-specialization)關系(通過繼承來表現),而對象之間的橫向關聯則完全用AOP來表現. 這樣,很多給對象之間橫向關聯增加靈活性的設計模式(例如Decorator)將不再必要.”,如圖:
                                           2.jpg

    Spring中的Ioc

    想一想以前在使用工廠模式的時候,在最早的情況下,每個工廠可能都是一個Singleton,生成對象的代碼被寫死在了類里面.后來人們覺這樣還是耦合程度太高,還不夠靈活.所以把對象的類名寫在一個XML文件里,這樣一來.問題又來了,每個工廠都有自己的讀取配置文件的代碼,通過讀取XML文件,或者通過讀取Properties,工廠里充滿了亂糟糟的和業務邏輯完全不相關的配置管理代碼,維護起來很不方便,.而Spring通過組件工廠把這些都集成在了一起,用一個統一的BeanFactory來管理這些配置,而且提供了更高一級的抽象:ApplicationContext

     

    Ioc好像很神奇的樣子,其實原理和實現都很簡單,就是將要使用的對象都用XML來定義,用反射來生成,用注射的方式來使用. 其實Ioc是工廠模式的升華,Ioc可以被看作是一個大工廠,只不過這個大工廠里要生成的對象都是在XML文件中給出定義的,然后利用Java“反射”編程,根據XML中給出的類名生成相應的對象。從實現來看,Ioc是把以前在工廠方法里寫死的對象生成代碼,改變為由XML文件來定義,也就是把工廠和對象生成這兩者獨立分隔開來,目的就是提高靈活性和可維護性。

    Template Method和回調在框架中的使用

    Template模式主要是用來解決這樣的一個問題:當你知道算法的具體步驟,但不知道如何去執行這些步驟.Template把如何執行這些步驟的方法都封裝成抽象的函數,并且提供一個正確的順序去執行這些步驟,而具體子類實現這些處理各個步驟的抽象方法.

     

    業務邏輯抽象到超類集中化就是所謂的”控制反轉”了.在傳統的類庫中,一般是由客戶端來調用類庫里的方法.而在這里,卻是框架控制了用戶流程,具體的子類只是要求履行一個明確的契約.在Spring中的MVC框架里,jdbc包里.都大量的使用了Template模式.

     

    Java中的回調函數主要是在實現事件驅動模型的時候使用的,但是在Spring里面,回調被賦予了新的意義:通過回調接口(函數)來實現可擴展性.如jdbc包的RowcallbackHandler.

    posted @ 2005-06-01 14:11 李嵐 閱讀(809) | 評論 (0)編輯 收藏


    2005年5月27日

         摘要: 大家在工作中也許會碰到這樣的情況,一個C語言程序,可能有十幾萬行代碼,讀取上百張的數據表,還要處理N多的業務邏輯   當你和你的小組實現了這樣一個系統之后,它工作的很好,這時,大家都長舒了一口氣.可是,哪知道惡夢才剛剛開始.   突然有一天,客戶會提出新的需求,通知要你新加一個功能,你不得不在程序里的初始化函數里,處理業務邏輯的函數里,還有掃尾的函數里都加上你要新添加的...  閱讀全文

    posted @ 2005-05-27 11:44 李嵐 閱讀(1531) | 評論 (0)編輯 收藏

         摘要: 前言 最近在看Spring MVC的源碼,就把自己對MVC模式和對各種框架的實現的認識寫出來給大家看看,算是一個總結.所以,懇請大家用懷疑的眼光來看待這篇文章,假如有認識不對的地方,麻煩指出. MVC與WEB應用 MVC是什么就不用我多說了.對于現有較成熟的Model-View-Control(MVC)框架而言,其注意的主要問題無外乎下面這些: Model: 模型應該包含由視圖顯示的數據...  閱讀全文

    posted @ 2005-05-27 11:29 李嵐 閱讀(3323) | 評論 (3)編輯 收藏


    僅列出標題  

    posts - 7, comments - 23, trackbacks - 0, articles - 0

    Copyright © 李嵐

    主站蜘蛛池模板: 日韩成人免费视频| 皇色在线免费视频| 无码国产精品久久一区免费| 亚洲国产精品无码久久久不卡| 国产成人精品亚洲| www.91亚洲| 国产精品无码永久免费888| 亚洲一级片免费看| 韩国免费a级作爱片无码| 亚洲伊人久久大香线蕉综合图片| 久久www免费人成看国产片 | 色吊丝最新永久免费观看网站| 久久久久亚洲国产| 成年美女黄网站色大免费视频| 亚洲av无码无线在线观看| 国产99视频免费精品是看6| 污视频网站免费观看| 亚洲日韩欧洲无码av夜夜摸| 午夜网站在线观看免费完整高清观看| 日韩亚洲Av人人夜夜澡人人爽 | 免费va人成视频网站全| 丰满少妇作爱视频免费观看| 亚洲人成网站在线观看播放| 222www免费视频| 亚洲人成网站999久久久综合| 永久久久免费浮力影院| 国产精品免费看久久久香蕉| 久久精品国产亚洲av高清漫画| 成熟女人牲交片免费观看视频| 国产亚洲人成在线影院| 久久久久久亚洲精品| 91免费精品国自产拍在线不卡| 麻豆一区二区三区蜜桃免费| 亚洲AV无码不卡在线播放| 男女超爽刺激视频免费播放 | 青青操免费在线观看| 亚洲一区精品视频在线| 亚洲第一网站男人都懂| 久久九九兔免费精品6| 日韩色日韩视频亚洲网站| 亚洲自偷自偷精品|