??xml version="1.0" encoding="utf-8" standalone="yes"?><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Ip" value="localhost"/>
<add key="Port" value="8888"/>
<add key="ServiceName" value="Indexer"/>
</appSettings>
</configuration>
头文件如下:
#pragma once
#include <string>
#include <map>
class AppConfig
{
public:
AppConfig(void);
~AppConfig(void);
int GetInt(std::string key);
std::string GetString(std::string key);
private:
std::map<std::string,std::string> config_map_;
};
extern AppConfig appConfig;
#include "AppConfig.h"
#include "Markup.h"
AppConfig appConfig;
AppConfig::AppConfig(void)
{
CMarkup parser;
if (!parser.Load( "App.Config" ))
{
return;
}
if (parser.FindChildElem("appSettings"))
{
parser.IntoElem();
while (parser.FindChildElem("add"))
{
std::string key = parser.GetChildAttrib("key");
std::string value = parser.GetChildAttrib("value");
config_map_[key] = value;
}
parser.OutOfElem();
}
}
AppConfig::~AppConfig(void)
{
}
int AppConfig::GetInt( std::string key )
{
if (config_map_.find(key) != config_map_.end())
{
return atoi(config_map_[key].c_str());
}
else
{
return 0;
}
}
std::string AppConfig::GetString( std::string key )
{
if (config_map_.find(key) != config_map_.end())
{
return config_map_[key];
}
else
{
return "";
}
}
试代码为:
// MarkupTest.cpp : 定义控制台应用程序的入口炏V?br>
//
#include "stdafx.h"
#include "AppConfig.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
cout << appConfig.GetString("Ip") << "-----" << appConfig.GetInt("Port") << "----" << appConfig.GetString("ServiceName") << endl;
return 0;
}
]]>
vs2008调试后控制台H口关不?010-07-29 16:19
最q用Visual Studio 2008 写一些控制台E序Q调试后的时候,当走到完成的时候,q个控制台程序的H口关不了了。再调试的时候就会出C个新的控制台E序?br>在Q务管理器q可以看到这个窗口,但是关不掉了。感觉这个控制台E序已经失控了?br>虽然q个对电(sh)脑运行没有媄响,但还是很不爽。而且最后关有问题,D不能x?br>扑ֈ一些相关的|页也讨论的Q最后结论是windows的一个更新KB978037Dcress.exeZ一些问题?br>解决办法Q删除KB978037更新Q删除的办法是在控制面板的添加或删除E序面板里,N显C更斎ͼ扑ֈKB978037更新Q删除?br>附别人的讨论记录Q?a >http://social.msdn.microsoft.com/Forums/en-US/vsdebug/thread/e6d4a4f5-7002-401a-90e1-6174d7f9e3ca/
]]>
使用说明Q?br> Q?Q源代码主要提供了MD5c,在类之外提供了两个函敎ͼ
std::string getMD5(std::ifstream& stream);//q个是文件接口,计算文g内容的MD5
std::string getMD5(const char* str,unsigned int str_len);//q个׃用说?br>想研I代码的话,参考MD5cȝ实现Q如果只是用的话Q只需会用上面的接口即?br> Q?Qstd::string getMD5(const char* str,unsigned int str_len)的用:
string sName = "MD5";
string sMD5 = getMD5(sName.c_str(),sName.length());
此时sMD5的gؓQ?f138a09169b250e9dcb378140907378
Q?Qstd::string getMD5(std::ifstream& stream)的用:创徏md5.txtQ内容ؓQMD5
ifstream file("md5.txt");
string sMD5File = getMD5(file);
sMD5File 的也是:7f138a09169b250e9dcb378140907378
Q?Qlinux下提供md5sum,上面的md5.txt传到l(f)inux下,然后Qmd5sum md5.txtQ结果和上面一栗注意,一定要认md5.txt内容?个字节,如果直接d上linuxQ用vi创徏md5.txtQ然后输?#8220;MD5”Q最后保存,q种方式linux下会q加一个空行,DMD5g一致?br> Q?Q安全意识要树立Q这个网?a >http://www.cmd5.com/以网Ş式提供md5解密Q将上面?f138a09169b250e9dcb378140907378的输入,几秒旉Q得到MD5
]]>
]]>
]]>
[tqg@localhost test]$ vi test.cpp
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void signal_handler(int sig)
{
printf("catch signal: %d,thread id = %u\n",sig,pthread_self());
pthread_exit(0);
}
void* thread_handler(void*arg)
{
signal(SIGQUIT,signal_handler);
printf("thread arg = %s\n",(char*)arg);
sleep(10);
printf("in thread\n");
return (void*)0;
}
int main()
{
char* pArg = "hello";
pthread_t tid;
pthread_create(&tid,NULL,thread_handler,pArg);
printf("main thread id = %u\n",pthread_self());
sleep(2);
printf("killing now\n");
pthread_kill(tid,SIGQUIT);
sleep(20);
printf("exit main now\n");
return 0;
}
~
~
~
~
"test.cpp" 42L, 648C written
[tqg@localhost test]$ g++ -o test test.cpp -lpthread
[tqg@localhost test]$ ./test
main thread id = 3086875296
thread arg = hello
killing now
catch signal: 3,thread id = 3086871472
exit main now
[tqg@localhost test]$
可以看出Q信号处理函数的执行是在要捕获信L子线Ethread_handler的上下文中执行的?/p>
8 sum+=i;
9 }
10 return sum;
11 }
12
13
14 main()
15 {
16 int i;
17 long result = 0;
18 for(i=1; i<=100; i++)
19 {
20 result += i;
21 }
22
23 printf("result[1-100] = %d \n", result );
24 printf("result[1-250] = %d \n", func(250) );
25 }
~译生成执行文gQ(Linux下)
hchen/test> cc -g tst.c -o tst
使用GDB调试Q?
hchen/test> gdb tst <---------- 启动GDB
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or 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.
This GDB was configured as "i386-suse-linux"...
(gdb) l <-------------------- l命o相当于listQ从W一行开始例出原码?
1 #include
2
3 int func(int n)
4 {
5 int sum=0,i;
6 for(i=0; i 7 {
8 sum+=i;
9 }
10 return sum;
(gdb) <-------------------- 直接回R表示Q重复上一ơ命?
11 }
12
13
14 main()
15 {
16 int i;
17 long result = 0;
18 for(i=1; i<=100; i++)
19 {
20 result += i;
(gdb) break 16 <-------------------- 讄断点Q在源程序第16行处?
Breakpoint 1 at 0x8048496: file tst.c, line 16.
(gdb) break func <-------------------- 讄断点Q在函数func()入口处?
Breakpoint 2 at 0x8048456: file tst.c, line 5.
(gdb) info break <-------------------- 查看断点信息?
Num Type Disp Enb Address What
1 breakpoint keep y 0x08048496 in main at tst.c:16
2 breakpoint keep y 0x08048456 in func at tst.c:5
(gdb) r <--------------------- q行E序Qrun命o?
Starting program: /home/hchen/test/tst
Breakpoint 1, main () at tst.c:17 <---------- 在断点处停住?
17 long result = 0;
(gdb) n <--------------------- 单条语句执行Qnext命o写?
18 for(i=1; i<=100; i++)
(gdb) n
20 result += i;
(gdb) n
18 for(i=1; i<=100; i++)
(gdb) n
20 result += i;
(gdb) c <--------------------- l箋q行E序Qcontinue命o写?
Continuing.
result[1-100] = 5050 <----------E序输出?
Breakpoint 2, func (n=250) at tst.c:5
5 int sum=0,i;
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p i <--------------------- 打印变量i的|print命o写?
$1 = 134513808
(gdb) n
8 sum+=i;
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p sum
$2 = 1
(gdb) n
8 sum+=i;
(gdb) p i
$3 = 2
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p sum
$4 = 3
(gdb) bt <--------------------- 查看函数堆栈?
#0 func (n=250) at tst.c:5
#1 0x080484e4 in main () at tst.c:24
#2 0x400409ed in __libc_start_main () from /lib/libc.so.6
(gdb) finish <--------------------- 退出函数?
Run till exit from #0 func (n=250) at tst.c:5
0x080484e4 in main () at tst.c:24
24 printf("result[1-250] = %d \n", func(250) );
Value returned is $6 = 31375
(gdb) c <--------------------- l箋q行?
Continuing.
result[1-250] = 31375 <----------E序输出?
Program exited with code 027. <--------E序退出,调试l束?
(gdb) q <--------------------- 退出gdb?
hchen/test>
好了Q有了以上的感性认识,q是让我们来pȝ地认识一下gdb吧?
使用GDB
———?
一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时Q我们必
要把调试信息加到可执行文g中。用编译器Qcc/gcc/g++Q的 -g 参数可以做到q一炏V?br>如:
> cc -g hello.c -o hello
> g++ -g hello.cpp -o hello
如果没有-gQ你看不见E序的函数名、变量名Q所代替的全是运行时的内存地址。当你用
-g把调试信息加入之后,q成功编译目标代码以后,让我们来看看如何用gdb来调试他?
启动GDB的方法有以下几种Q?
1、gdb
program也就是你的执行文Ӟ一般在当然目录下?
2、gdb core
用gdb同时调试一个运行程序和core文gQcore是程序非法执行后core dump后生的文g?
3、gdb
如果你的E序是一个服务程序,那么你可以指定这个服务程序运行时的进EID。gdb会自
动attach上去Qƈ调试他。program应该在PATH环境变量中搜索得到?
GDB启动Ӟ可以加上一些GDB的启动开养I详细的开兛_以用gdb -help查看。我在下
面只例D一些比较常用的参数Q?
-symbols
-s
从指定文件中dW号表?
-se file
从指定文件中dW号表信息,q把他用在可执行文g中?
-core
-c
调试时core dump的core文g?
-directory
-d
加入一个源文g的搜索\径。默认搜索\径是环境变量中PATH所定义的\径?
GDB的命令概?
——————?
启动gdb后,׃被带入gdb的调试环境中Q就可以使用gdb的命令开始调试程序了Qgdb
的命令可以用help命o来查看,如下所C:
/home/hchen> gdb
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or 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.
This GDB was configured as "i386-suse-linux".
(gdb) help
List of classes of commands:
aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands
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)
gdb的命令很多,gdb把之分成许多个种cRhelp命o只是例出gdb的命令种c,如果要看
U类中的命oQ可以用help 命oQ如Qhelp breakpointsQ查看设|断点的所有命令。也
可以直接help 来查看命令的帮助?
gdb中,输入命oӞ可以不用打全命oQ只用打命o的前几个字符可以了Q当Ӟ命o
的前几个字符应该要标志着一个唯一的命令,在Linux下,你可以敲MơTAB键来补齐
命o的全Uͼ如果有重复的Q那么gdb会把其例出来?
CZ一Q在q入函数funcӞ讄一个断炏V可以敲入break funcQ或是直接就是b func
(gdb) b func
Breakpoint 1 at 0x8048458: file hello.c, line 10.
CZ二:敲入b按两ơTAB键,你会看到所有b打头的命令:
(gdb) b
backtrace break bt
(gdb)
CZ三:只记得函数的前缀Q可以这P
(gdb) b make_ <按TAB?gt;
Q再按下一ơTAB键,你会看到:Q?
make_a_section_from_file make_environ
make_abs_section make_function_type
make_blockvector make_pointer_type
make_cleanup make_reference_type
make_command make_symbol_completion_list
(gdb) b make_
GDB把所有make开头的函数全部例出来给你查看?
CZ四:调试C++的程序时Q有可以函数名一栗如Q?
(gdb) b 'bubble( M-?
bubble(double,double) bubble(int,int)
(gdb) b 'bubble(
你可以查看到C++中的所有的重蝲函数及参数。(注:M-??#8220;按两ơTAB?#8221;是一个意思)
要退出gdbӞ只用发quit或命令简Uqp了?
GDB中运行UNIX的shellE序
———————————?
在gdb环境中,你可以执行UNIX的shell的命令,使用gdb的shell命o来完成:
shell
调用UNIX的shell来执行,环境变量SHELL中定义的UNIX的shell会被用来执行,?br>果SHELL没有定义Q那׃用UNIX的标准shellQ?bin/sh。(在Windows中用Command.com
或cmd.exeQ?
q有一个gdb命o是makeQ?
make
可以在gdb中执行make命o来重新build自己的程序。这个命令等价于“shell make ”?
在GDB中运行程?
———————?
当以gdb 方式启动gdb后,gdb会在PATH路径和当前目录中搜烦的源文g。如要确认gdb
是否d源文Ӟ可用l或list命oQ看看gdb是否能列出源代码?
在gdb中,q行E序使用r或是run命o。程序的q行Q你有可能需要设|下面四斚w的事?
1、程序运行参数?
set args 可指定运行时参数。(如:set args 10 20 30 40 50Q?
show args 命o可以查看讄好的q行参数?
2、运行环境?
path
可设定程序的q行路径?
show paths 查看E序的运行\径?
set environment varname [=value] 讄环境变量。如Qset env USER=hchen
show environment [varname] 查看环境变量?
3、工作目录?
cd
相当于shell的cd命o?
pwd 昄当前的所在目录?
4、程序的输入输出?
info terminal 昄你程序用到的l端的模式?
使用重定向控制程序输出。如Qrun > outfile
tty命o可以指写输入输出的终端设备。如Qtty /dev/ttyb
调试已运行的E序
———————?
两种Ҏ(gu)Q?
1、在UNIX下用ps查看正在q行的程序的PIDQ进EIDQ,然后用gdb PID格式挂接正在
q行的程序?
2、先用gdb 兌上源代码Qƈq行gdbQ在gdb中用attach命o来挂接进E的PID。ƈ?br>detach来取消挂接的q程?
暂停 / 恢复E序q行
————————?
调试E序中,暂停E序q行是必ȝQGDB可以方便地暂停程序的q行。你可以讄E序
的在哪行停住Q在什么条件下停住Q在收到什么信h停往{等。以便于你查看运行时的变
量,以及q行时的程?
当进E被gdb停住Ӟ你可以用info program 来查看程序的是否在运行,q程P被暂?br>的原因?
在gdb中,我们可以有以下几U暂停方式:断点QBreakPointQ、观察点QWatchPointQ、捕
捉点QCatchPointQ、信PSignalsQ、线E停止(Thread StopsQ。如果要恢复E序q行Q可
以用c或是continue命o?
一、设|断点(BreakPointQ?
我们用break命o来设|断炏V正面有几点讄断点的方法:
break
在进入指定函数时停住。C++中可以用class::function或function(type,type)格式来指定函
数名?
break
在指定行号停住?
break +offset
break -offset
在当前行L前面或后面的offset行停住。offiset然数?
break filename:linenum
在源文gfilename的linenum行处停住?
break filename:function
在源文gfilename的function函数的入口处停住?
break *address
在程序运行的内存地址处停住?
break
break命o没有参数Ӟ表示在下一条指令处停住?
break ... if
...可以是上q的参数Qcondition表示条gQ在条g成立时停住。比如在循环境体中,可以?br>|break if i=100Q表C当i?00时停住程序?
查看断点Ӟ可用info命oQ如下所C:Q注Qn表示断点P
info breakpoints [n]
info break [n]
二、设|观察点QWatchPointQ?
观察点一般来观察某个表达式(变量也是一U表辑ּQ的值是否有变化了,如果有变化,?br>上停住程序。我们有下面的几U方法来讄观察点:
watch
辑ּQ变量)expr讄一个观察点。一量表辑ּ值有变化Ӟ马上停住E序?
rwatch
当表辑ּQ变量)expr被读Ӟ停住E序?
awatch
当表辑ּQ变量)的DL被写Ӟ停住E序?
info watchpoints
列出当前所讄了的所有观察点?
三、设|捕捉点QCatchPointQ?
你可讄捕捉Ҏ(gu)补捉E序q行时的一些事件。如Q蝲入共享库Q动态链接库Q或是C++
的异常。设|捕捉点的格式ؓQ?
catch
当event发生Ӟ停住E序。event可以是下面的内容Q?
1、throw 一个C++抛出的异常。(throw为关键字Q?
2、catch 一个C++捕捉到的异常。(catch为关键字Q?
3、exec 调用pȝ调用exec时。(exec为关键字Q目前此功能只在HP-UX下有用)
4、fork 调用pȝ调用fork时。(fork为关键字Q目前此功能只在HP-UX下有用)
5、vfork 调用pȝ调用vfork时。(vfork为关键字Q目前此功能只在HP-UX下有用)
6、load ?load 载入׃n库(动态链接库Q时。(load为关键字Q目前此功能只在HP-UX
下有用)
7、unload ?unload 卸蝲׃n库(动态链接库Q时。(unload为关键字Q目前此功能只在
HP-UX下有用)
tcatch
只设|一ơ捕捉点Q当E序停住以后Q应点被自动删除?
四、维护停止点
上面说了如何讄E序的停止点QGDB中的停止点也是上述的三cR在GDB中,如果?br>觉得已定义好的停止点没有用了Q你可以使用delete、clear、disable、enableq几个命令来
q行l护?
clear
清除所有的已定义的停止炏V?
clear
clear
清除所有设|在函数上的停止炏V?
clear
clear
清除所有设|在指定行上的停止点?
delete [breakpoints] [range...]
删除指定的断点,breakpoints为断点号。如果不指定断点P则表C删除所有的断点。range
表示断点L范围Q如Q?-7Q。其写命令ؓd?
比删除更好的一U方法是disable停止点,disable了的停止点,GDB不会删除Q当你还需?br>Ӟenable卛_Q就好像回收站一栗?
disable [breakpoints] [range...]
disable所指定的停止点Qbreakpoints为停止点受如果什么都不指定,表示disable所有的
停止炏V简写命令是dis.
enable [breakpoints] [range...]
enable所指定的停止点Qbreakpoints为停止点受?
enable [breakpoints] once range...
enable所指定的停止点一ơ,当程序停止后Q该停止炚w上被GDB自动disable?
enable [breakpoints] delete range...
enable所指定的停止点一ơ,当程序停止后Q该停止炚w上被GDB自动删除?
五、停止条件维?
前面在说到设|断Ҏ(gu)Q我们提到过可以讄一个条Ӟ当条件成立时Q程序自动停止,q?br>是一个非常强大的功能Q这里,我想专门说说q个条g的相关维护命令。一般来_为断?br>讄一个条Ӟ我们使用if关键词,后面跟其断点条g。ƈ且,条g讄好后Q我们可?br>用condition命o来修Ҏ(gu)点的条g。(只有break和watch命o支持ifQcatch目前暂不支持
ifQ?
condition
修改断点号ؓbnum的停止条件ؓexpression?
condition
清除断点号ؓbnum的停止条件?
q有一个比较特D的l护命oignoreQ你可以指定E序q行Ӟ忽略停止条g几次?
ignore
表示忽略断点号ؓbnum的停止条件countơ?
六、ؓ停止点设定运行命?
我们可以使用GDB提供的command命o来设|停止点的运行命令。也是_当运行的
E序在被停止住时Q我们可以让其自动运行一些别的命令,q很有利行自动化调试。对Z
GDB的自动化调试是一个强大的支持?
commands [bnum]
... command-list ...
end
为断点号bnum指写一个命令列表。当E序被该断点停住Ӟgdb会依ơ运行命令列表中?br>命o?
例如Q?
break foo if x>0
commands
printf "x is %d\n",x
continue
end
断点讄在函数foo中,断点条g是x>0Q如果程序被断住后,也就是,一旦x的值在foo
函数中大?QGDB会自动打印出x的|ql运行程序?
如果你要清除断点上的命o序列Q那么只要简单的执行一下commands命oQƈ直接在打?br>endp了?
七、断点菜?
在C++中,可能会重复出现同一个名字的函数若干ơ(函数重蝲Q,在这U情况下Qbreak ?br>能告诉GDB要停在哪个函数的入口。当Ӟ你可以用break 也就是把函数的参数类型告
诉GDBQ以指定一个函数。否则的话,GDB会给你列Z个断点菜单供你选择你所需要的
断点。你只要输入你菜单列表中的编号就可以了。如Q?
(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.cc; line number:853
[6] file:String.cc; line number:846
[7] file:String.cc; line number:735
> 2 4 6
Breakpoint 1 at 0xb26c: file String.cc, line 867.
Breakpoint 2 at 0xb344: file String.cc, line 875.
Breakpoint 3 at 0xafcc: file String.cc, line 846.
Multiple breakpoints were set.
Use the "delete" command to delete unwanted
breakpoints.
(gdb)
可见QGDB列出了所有after的重载函敎ͼ你可以选一下列表编号就行了?表示攑ּ讄
断点Q?表示所有函数都讄断点?
八、恢复程序运行和单步调试
当程序被停住了,你可以用continue命o恢复E序的运行直到程序结束,或下一个断点到来?br>也可以用step或next命o单步跟踪E序?
continue [ignore-count]
c [ignore-count]
fg [ignore-count]
恢复E序q行Q直到程序结束,或是下一个断点到来。ignore-count表示忽略其后的断Ҏ(gu)
数。continueQcQfg三个命o都是一L意思?
step
单步跟踪Q如果有函数调用Q他会进入该函数。进入函数的前提是,此函数被~译有debug
信息。很像VC{工具中的step in。后面可以加count也可以不加,不加表示一条条地执行,
加表C执行后面的count条指令,然后再停住?
next
同样单步跟踪Q如果有函数调用Q他不会q入该函数。很像VC{工具中的step over。后?br>可以加count也可以不加,不加表示一条条地执行,加表C执行后面的count条指令,然后
再停住?
set step-mode
set step-mode on
打开step-mode模式Q于是,在进行单步跟t时Q程序不会因为没有debug信息而不停住?br>q个参数有很利于查看机器码?
set step-mod off
关闭step-mode模式?
finish
q行E序Q直到当前函数完成返回。ƈ打印函数q回时的堆栈地址和返回值及参数值等信息?
until ?u
当你厌倦了在一个@环体内单步跟t时Q这个命令可以运行程序直到退出@环体?
stepi ?si
nexti ?ni
单步跟踪一条机器指令!一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步
执行机器指o。与之一h相同功能的命令是“display/i $pc” Q当q行完这个命令后Q单
步跟t会在打出程序代码的同时打出机器指oQ也是汇编代码Q?
?ji)、信PSignalsQ?
信号是一UY中断Q是一U处理异步事件的Ҏ(gu)。一般来_操作pȝ都支持许多信受尤
其是UNIXQ比较重要应用程序一般都会处理信受UNIX定义了许多信P比如SIGINT
表示中断字符信号Q也是Ctrl+C的信PSIGBUS表示g故障的信PSIGCHLD表示
子进E状态改变信PSIGKILL表示l止E序q行的信P{等。信号量~程是UNIX?br>非常重要的一U技术?
GDB有能力在你调试程序的时候处理Q何一U信P你可以告诉GDB需要处理哪一U信
受你可以要求GDB收到你所指定的信hQ马上停住正在运行的E序Q以供你q行调试?br>你可以用GDB的handle命o来完成这一功能?
handle
在GDB中定义一个信号处理。信号可以以SIG开头或不以SIG开_可以用定义一个要?br>理信L范围Q如QSIGIO-SIGKILLQ表C处理从SIGIO信号到SIGKILL的信P其中?br>括SIGIOQSIGIOTQSIGKILL三个信号Q,也可以用关键字all来标明要处理所有的信号?br>一旦被调试的程序接收到信号Q运行程序马上会被GDB停住Q以供调试。其可以是以下几
U关键字的一个或多个?
nostop
当被调试的程序收ChQGDB不会停住E序的运行,但会打出消息告诉你收到这U信
受?
stop
当被调试的程序收ChQGDB会停住你的程序?
print
当被调试的程序收ChQGDB会显C出一条信息?
noprint
当被调试的程序收ChQGDB不会告诉你收CL信息?
pass
noignore
当被调试的程序收ChQGDB不处理信受这表示QGDB会把q个信号交给被调试程
序会处理?
nopass
ignore
当被调试的程序收ChQGDB不会让被调试E序来处理这个信受?
info signals
info handle
查看有哪些信号在被GDB中?
十、线E(Thread StopsQ?
如果你程序是多线E的话,你可以定义你的断Ҏ(gu)否在所有的U程上,或是在某个特定的U?br>E。GDB很容易帮你完成这一工作?
break thread
break thread if ...
linespec指定了断点设|在的源E序的行受threadno指定了线E的IDQ注意,q个ID?br>GDB分配的,你可以通过“info threads”命o来查看正在运行程序中的线E信息。如果你
不指定thread 则表CZ的断点设在所有线E上面。你q可以ؓ某线E指定断Ҏ(gu)件。如Q?
(gdb) break frik.c:13 thread 28 if bartab > lim
当你的程序被GDB停住Ӟ所有的q行U程都会被停住。这方便你你查看q行E序的M
情况。而在你恢复程序运行时Q所有的U程也会被恢复运行。那怕是主进E在被单步调试时?
查看栈信?
————?
当程序被停住了,你需要做的第一件事是查看E序是在哪里停住的。当你的E序调用了一
个函敎ͼ函数的地址Q函数参敎ͼ函数内的局部变量都会被压入“?#8221;QStackQ中。你可以
用GDB命o来查看当前的栈中的信息?
下面是一些查看函数调用栈信息的GDB命oQ?
backtrace
bt
打印当前的函数调用栈的所有信息。如Q?
(gdb) bt
#0 func (n=250) at tst.c:6
#1 0x08048524 in main (argc=1, argv=0xbffff674) at tst.c:30
#2 0x400409ed in __libc_start_main () from /lib/libc.so.6
从上可以看出函数的调用栈信息Q__libc_start_main --> main() --> func()
backtrace
bt
n是一个正整数Q表C只打印栈顶上n层的栈信息?
backtrace <-n>
bt <-n>
-n表一个负整数Q表C只打印栈底下n层的栈信息?
如果你要查看某一层的信息Q你需要在切换当前的栈Q一般来_E序停止Ӟ最层的栈
是当前栈,如果你要查看栈下面层的详l信息,首先要做的是切换当前栈?
frame
f
n是一个从0开始的整数Q是栈中的层~号。比如:frame 0Q表C栈Ӟframe 1Q表C栈?br>W二层?
up
表示向栈的上面移动n层,可以不打nQ表C向上移动一层?
down
表示向栈的下面移动n层,可以不打nQ表C向下移动一层?
上面的命令,都会打印出移动到的栈层的信息。如果你不想让其打出信息。你可以使用q三
个命令:
select-frame 对应?frame 命o?
up-silently 对应?up 命o?
down-silently 对应?down 命o?
查看当前栈层的信息,你可以用以下GDB命oQ?
frame ?f
会打印出q些信息Q栈的层~号Q当前的函数名,函数参数|函数所在文件及行号Q函?br>执行到的语句?
info frame
info f
q个命o会打印出更ؓ详细的当前栈层的信息Q只不过Q大多数都是q行时的内内地址。比
如:函数地址Q调用函数的地址Q被调用函数的地址Q目前的函数是由什么样的程序语a?br>成的、函数参数地址及倹{局部变量的地址{等。如Q?
(gdb) info f
Stack level 0, frame at 0xbffff5d4:
eip = 0x804845d in func (tst.c:6); saved eip 0x8048524
called by frame at 0xbffff60c
source language c.
Arglist at 0xbffff5d4, args: n=250
Locals at 0xbffff5d4, Previous frame's sp is 0x0
Saved registers:
ebp at 0xbffff5d4, eip at 0xbffff5d8
info args
打印出当前函数的参数名及其倹{?
info locals
打印出当前函C所有局部变量及其倹{?
info catch
打印出当前的函数中的异常处理信息?
查看源程?
————?
一、显C源代码
GDB 可以打印出所调试E序的源代码Q当Ӟ在程序编译时一定要加上-g的参敎ͼ把源E?br>序信息编译到执行文g中。不然就看不到源E序了。当E序停下来以后,GDB会报告程?br>停在了那个文件的W几行上。你可以用list命o来打印程序的源代码。还是来看一看查看源
代码的GDB命o吧?
list
昄E序Wlinenum行的周围的源E序?
list
昄函数名ؓfunction的函数的源程序?
list
昄当前行后面的源程序?
list -
昄当前行前面的源程序?
一般是打印当前行的?行和?行,如果昄函数是是?行下8行,默认?0行,?br>Ӟ你也可以定制昄的范_使用下面命o可以讄一ơ显C源E序的行数?
set listsize
讄一ơ显C源代码的行数?
show listsize
查看当前listsize的设|?
list命oq有下面的用法:
list ,
昄从first行到l(f)ast行之间的源代码?
list ,
昄从当前行到l(f)ast行之间的源代码?
list +
往后显C源代码?
一般来说在list后面可以跟以下这们的参数Q?
行号?
<+offset> 当前行号的正偏移量?
<-offset> 当前行号的负偏移量?
哪个文g的哪一行?
函数名?
哪个文g中的哪个函数?
<*address> E序q行时的语句在内存中的地址?
二、搜索源代码
不仅如此QGDBq提供了源代码搜索的命oQ?
forward-search
search
向前面搜索?
reverse-search
全部搜烦?
其中Q就是正则表辑ּQ也M个字W串的匹配模式,关于正则表达式,我就不在q里讲了Q?br>q请各位查看相关资料?
三、指定源文g的\?
某些时候,?g~译q后的执行程序中只是包括了源文g的名字,没有路径名。GDB提供
了可以让你指定源文g的\径的命oQ以便GDBq行搜烦?
directory
dir
加一个源文g路径到当前\径的前面。如果你要指定多个\径,UNIX下你可以使用“:”Q?br>Windows下你可以使用“;”?
directory
清除所有的自定义的源文件搜索\径信息?
show directories
昄定义了的源文件搜索\径?
四、源代码的内?
你可以用info line命o来查看源代码在内存中的地址。info line后面可以?#8220;行号”Q?#8220;?br>数名”Q?#8220;文g?行号”Q?#8220;文g?函数?#8221;Q这个命令会打印出所指定的源码在q行时的?br>存地址Q如Q?
(gdb) info line tst.c:func
Line 5 of "tst.c" starts at address 0x8048456 and ends at 0x804845d .
q有一个命令(disassembleQ你可以查看源程序的当前执行时的机器码,q个命o会把目前
内存中的指odump出来。如下面的示例表C查看函数func的汇~代码?
(gdb) disassemble func
Dump of assembler code for function func:
0x8048450 : push %ebp
0x8048451 : mov %esp,%ebp
0x8048453 : sub $0x18,%esp
0x8048456 : movl $0x0,0xfffffffc(%ebp)
0x804845d : movl $0x1,0xfffffff8(%ebp)
0x8048464 : mov 0xfffffff8(%ebp),%eax
0x8048467 : cmp 0x8(%ebp),%eax
0x804846a : jle 0x8048470
0x804846c : jmp 0x8048480
0x804846e : mov %esi,%esi
0x8048470 : mov 0xfffffff8(%ebp),%eax
0x8048473 : add %eax,0xfffffffc(%ebp)
0x8048476 : incl 0xfffffff8(%ebp)
0x8048479 : jmp 0x8048464
0x804847b : nop
0x804847c : lea 0x0(%esi,1),%esi
0x8048480 : mov 0xfffffffc(%ebp),%edx
0x8048483 : mov %edx,%eax
0x8048485 : jmp 0x8048487
0x8048487 : mov %ebp,%esp
0x8048489 : pop %ebp
0x804848a : ret
End of assembler dump.
查看q行时数?
——————?
在你调试E序Ӟ当程序被停住Ӟ你可以用print命oQ简写命令ؓpQ,或是同义命o
inspect来查看当前程序的q行数据。print命o的格式是Q?
print
print /
是表辑ּQ是你所调试的程序的语言的表辑ּQGDB可以调试多种~程语言Q,是输出的?br>式,比如Q如果要把表辑ּ?6q制的格式输出,那么是/x?
一、表辑ּ
print和许多GDB的命令一P可以接受一个表辑ּQGDB会根据当前的E序q行的数?br>来计这个表辑ּQ既然是表达式,那么可以是当前E序q行中的const帔R、变量、函
数等内容。可惜的是GDB不能使用你在E序中所定义的宏?
表达式的语法应该是当前所调试的语a的语法,׃C/C++是一U大众型的语aQ所以,?br>文中的例子都是关于C/C++的。(而关于用GDB调试其它语言的章节,我将在后面介l)
在表辑ּ中,有几UGDB所支持的操作符Q它们可以用在Q何一U语a中?
@
是一个和数组有关的操作符Q在后面会有更详l的说明?
::
指定一个在文g或是一个函C的变量?
{}
表示一个指向内存地址的类型ؓtype的一个对象?
二、程序变?
在GDB中,你可以随时查看以下三U变量的|
1、全局变量Q所有文件可见的Q?
2、静态全局变量Q当前文件可见的Q?
3、局部变量(当前Scope可见的)
如果你的局部变量和全局变量发生冲突Q也是重名Q,一般情况下是局部变量会隐藏全局
变量Q也是_如果一个全局变量和一个函C的局部变量同名时Q如果当前停止点在函
CQ用print昄出的变量的g是函C的局部变量的倹{如果此时你x看全局变量
的值时Q你可以使用“::”操作W:
file::variable
function::variable
可以通过q种形式指定你所x看的变量Q是哪个文g中的或是哪个函数中的。例如,查看
文gf2.c中的全局变量x的|
gdb) p 'f2.c'::x
当然Q?#8220;::”操作W会和C++中的发生冲突QGDB能自动识?#8220;::” 是否C++的操作符Q所
以你不必担心在调试C++E序时会出现异常?
另外Q需要注意的是,如果你的E序~译时开启了优化选项Q那么在用GDB调试被优化过
的程序时Q可能会发生某些变量不能讉KQ或是取值错误码的情c这个是很正常的Q因?br>优化E序会删改你的程序,整理你程序的语句序Q剔除一些无意义的变量等Q所以在GDB
调试q种E序Ӟq行时的指o和你所~写指o有不一P也就会出C所惌不到的结
果。对付这U情冉|Q需要在~译E序时关闭编译优化。一般来_几乎所有的~译器都?br>持编译优化的开养I例如QGNU的C/C++~译器GCCQ你可以使用“-gstabs”选项来解?br>q个问题。关于编译器的参敎ͼq请查看~译器的使用说明文档?
三、数l?
有时候,你需要查看一D连l的内存I间的倹{比如数l的一D,或是动态分配的数据的大
。你可以使用GDB?#8220;@”操作W,“@”的左Ҏ(gu)W一个内存的地址的|“@”的右
边则你你x看内存的长度。例如,你的E序中有q样的语句:
int *array = (int *) malloc (len * sizeof (int));
于是Q在GDB调试q程中,你可以以如下命o昄个动态数l的取|
p *array@len
@的左Ҏ(gu)数组的首地址的|也就是变量array所指向的内容,双则是数据的长度,?br>保存在变量len中,其输出结果,大约是下面这个样子的Q?
(gdb) p *array@len
$1 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40}
如果是静态数l的话,可以直接用print数组名,可以显C数l中所有数据的内容了?
四、输出格?
一般来_GDB会根据变量的cd输出变量的倹{但你也可以自定义GDB的输出的格式?br>例如Q你惌Z个整数的十六q制Q或是二q制来查看这个整型变量的中的位的情况。要
做到q样Q你可以使用GDB的数据显C格式:
x 按十六进制格式显C变量?
d 按十q制格式昄变量?
u 按十六进制格式显C无W号整型?
o 按八q制格式昄变量?
t 按二q制格式昄变量?
a 按十六进制格式显C变量?
c 按字W格式显C变量?
f 按QҎ(gu)格式昄变量?
(gdb) p i
$21 = 101
(gdb) p/a i
$22 = 0x65
(gdb) p/c i
$23 = 101 'e'
(gdb) p/f i
$24 = 1.41531145e-43
(gdb) p/x i
$25 = 0x65
(gdb) p/t i
$26 = 1100101
五、查看内?
你可以用examine命oQ简写是xQ来查看内存地址中的倹{x命o的语法如下所C:
x/
n、f、u是可选的参数?
n 是一个正整数Q表C显C内存的长度Q也是说从当前地址向后昄几个地址的内宏V?
f 表示昄的格式,参见上面。如果地址所指的是字W串Q那么格式可以是sQ如果地十是
指o地址Q那么格式可以是i?
u 表示从当前地址往后请求的字节敎ͼ如果不指定的话,GDB默认?个bytes。u参数?br>以用下面的字W来代替Qb表示单字节,h表示双字节,w表示四字节,g表示八字节。当
我们指定了字节长度后QGDB会从指内存定的内存地址开始,d指定字节Qƈ把其当作
一个值取出来?
表示一个内存地址?
n/f/u三个参数可以一起用。例如:
命oQx/3uh 0x54320 表示Q从内存地址0x54320d内容Qh表示以双字节Z个单位,3
表示三个单位Qu表示按十六进制显C?
六、自动显C?
你可以设|一些自动显C的变量Q当E序停住Ӟ或是在你单步跟踪Ӟq些变量会自动显
C。相关的GDB命o是display?
display
display/
display/
expr是一个表辑ּQfmt表示昄的格式,addr表示内存地址Q当你用display讑֮好了一
个或多个表达式后Q只要你的程序被停下来,GDB会自动显CZ所讄的这些表辑ּ的倹{?
格式i和s同样被display支持Q一个非常有用的命o是:
display/i $pc
$pc是GDB的环境变量,表示着指o的地址Q?i则表C出格式ؓ机器指o码,也就是汇
~。于是当E序停下后,׃出现源代码和机器指o码相对应的情形,q是一个很有意思的
功能?
下面是一些和display相关的GDB命oQ?
undisplay
delete display
删除自动昄Qdnums意ؓ所讄好了的自动显式的~号。如果要同时删除几个Q编号可?br>用空格分隔,如果要删除一个范围内的编P可以用减可C(如:2-5Q?
disable display
enable display
disable和enalbe不删除自动显C的讄Q而只是让其失效和恢复?
info display
查看display讄的自动显C的信息。GDB会打Z张表|向你报告当然调试中设|了?br>个自动昄讄Q其中包括,讄的编P表达式,是否enable?
七、设|显C选项
GDB中关于显C的选项比较多,q里我只例D大多数常用的选项?
set print address
set print address on
打开地址输出Q当E序昄函数信息ӞGDB会显出函数的参数地址。系l默认ؓ打开的,
如:
(gdb) f
#0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>")
at input.c:530
530 if (lquote != def_lquote)
set print address off
关闭函数的参数地址昄Q如Q?
(gdb) set print addr off
(gdb) f
#0 set_quotes (lq="<<", rq=">>") at input.c:530
530 if (lquote != def_lquote)
show print address
查看当前地址昄选项是否打开?
set print array
set print array on
打开数组昄Q打开后当数组昄Ӟ每个元素占一行,如果不打开的话Q每个元素则以?br>号分隔。这个选项默认是关闭的。与之相关的两个命o如下Q我׃再多说了?
set print array off
show print array
set print elements
q个选项主要是设|数l的Q如果你的数l太大了Q那么就可以指定一个来指定数据昄?br>最大长度,当到达这个长度时QGDB׃再往下显CZ。如果设|ؓ0Q则表示不限制?
show print elements
查看print elements的选项信息?
set print null-stop
如果打开了这个选项Q那么当昄字符串时Q遇到结束符则停止显C。这个选项默认为off?
set print pretty on
如果打开printf prettyq个选项Q那么当GDB昄l构体时会比较漂亮。如Q?
$1 = {
next = 0x0,
flags = {
sweet = 1,
sour = 1
},
meat = 0x54 "Pork"
}
set print pretty off
关闭printf prettyq个选项QGDB昄l构体时会如下显C:
$1 = {next = 0x0, flags = {sweet = 1, sour = 1}, meat = 0x54 "Pork"}
show print pretty
查看GDB是如何显C结构体的?
set print sevenbit-strings
讄字符昄Q是否按“\nnn”的格式显C,如果打开Q则字符串或字符数据按\nnn昄Q?br>?#8220;\065”?
show print sevenbit-strings
查看字符昄开x否打开?
set print union
讄昄l构体时Q是否显式其内的联合体数据。例如有以下数据l构Q?
typedef enum {Tree, Bug} Species;
typedef enum {Big_tree, Acorn, Seedling} Tree_forms;
typedef enum {Caterpillar, Cocoon, Butterfly}
Bug_forms;
struct thing {
Species it;
union {
Tree_forms tree;
Bug_forms bug;
} form;
};
struct thing foo = {Tree, {Acorn}};
当打开q个开xQ执?p foo 命o后,会如下显C:
$1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
当关闭这个开xQ执?p foo 命o后,会如下显C:
$1 = {it = Tree, form = {...}}
show print union
查看联合体数据的昄方式
set print object
在C++中,如果一个对象指针指向其zc,如果打开q个选项QGDB会自动按照虚Ҏ(gu)
调用的规则显C出,如果关闭q个选项的话QGDB׃虚函数表了。这个选项默认?br>off?
show print object
查看对象选项的设|?
set print static-members
q个选项表示Q当昄一个C++对象中的内容是,是否昄其中的静态数据成员。默认是
on?
show print static-members
查看静态数据成员选项讄?
set print vtbl
当此选项打开ӞGDB用比较规整的格式来昄虚函数表时。其默认是关闭的?
show print vtbl
查看虚函数显C格式的选项?
八、历史记?
当你用GDB的print查看E序q行时的数据Ӟ你每一个print都会被GDB记录下来。GDB
会以$1, $2, $3 .....q样的方式ؓ你每一个print命o~上受于是,你可以用这个编可?br>以前的表辑ּQ如$1。这个功能所带来的好处是Q如果你先前输入了一个比较长的表辑ּQ?br>如果你还x看这个表辑ּ的|你可以用历史记录来讉KQ省M重复输入?
?ji)、GDB环境变量
你可以在GDB的调试环境中定义自己的变量,用来保存一些调试程序中的运行数据。要?br>义一个GDB的变量很单只需。用GDB的set命o。GDB的环境变量和UNIX一P
也是?起头。如Q?
set $foo = *object_ptr
使用环境变量ӞGDB会在你第一ơ用时创徏q个变量Q而在以后的用中Q则直接?br>其c倹{环境变量没有类型,你可以给环境变量定义M的类型。包括结构体和数l?
show convenience
该命令查看当前所讄的所有的环境变量?
q是一个比较强大的功能Q环境变量和E序变量的交互用,得程序调试更为灵zM捗?br>例如Q?
set $i = 0
print bar[$i++]->contents
于是Q当你就不必Qprint bar[0]->contents, print bar[1]->contents地输入命令了。输入这L
命o后,只用敲回车,重复执行上一条语句,环境变量会自动篏加,从而完成逐个输出的功
能?
十、查看寄存器
要查看寄存器的|很简单,可以使用如下命oQ?
info registers
查看寄存器的情况。(除了点寄存器)
info all-registers
查看所有寄存器的情c(包括点寄存器)
info registers
查看所指定的寄存器的情c?
寄存器中攄了程序运行时的数据,比如E序当前q行的指令地址QipQ,E序的当前堆?br>地址QspQ等{。你同样可以使用print命o来访问寄存器的情况,只需要在寄存器名字前
加一?W号可以了。如Qp $eip?
改变E序的执?
——————?
一旦用GDB挂上被调试程序,当程序运行v来后Q你可以Ҏ(gu)自己的调试思\来动态地
在GDB中更改当前被调试E序的运行线路或是其变量的|q个强大的功能能够让你更?br>的调试你的程序,比如Q你可以在程序的一ơ运行中走遍E序的所有分支?
一、修改变量?
修改被调试程序运行时的变量|在GDB中很Ҏ(gu)实现Q用GDB的print命o卛_完成?br>如:
(gdb) print x=4
x=4q个表达式是C/C++的语法,意ؓ把变量x的g改ؓ4Q如果你当前调试的语a?br>PascalQ那么你可以使用Pascal的语法:x:=4?
在某些时候,很有可能你的变量和GDB中的参数冲突Q如Q?
(gdb) whatis width
type = double
(gdb) p width
$4 = 13
(gdb) set width=47
Invalid syntax in expression.
因ؓQset width是GDB的命令,所以,出现?#8220;Invalid syntax in expression”的设|错误,
此时Q你可以使用set var命o来告诉GDBQwidth不是你GDB的参敎ͼ而是E序的变量名Q?br>如:
(gdb) set var width=47
另外Q还可能有些情况QGDBq不报告q种错误Q所以保险v见,在你改变E序变量取?br>Ӟ最好都使用set var格式的GDB命o?
二、蟩转执?
一般来_被调试程序会按照E序代码的运行顺序依ơ执行。GDB提供了ؕ序执行的功能Q?br>也就是说QGDB可以修改E序的执行顺序,可以让程序执行随意蟩跃。这个功能可以由GDB
的jump命o来完Q?
jump
指定下一条语句的q行炏V可以是文g的行P可以是file:line格式Q可以是+numq种?br>U量格式。表式着下一条运行语句从哪里开始?
jump
q里?
是代码行的内存地址?
注意Qjump命o不会改变当前的程序栈中的内容Q所以,当你从一个函数蟩到另一个函?br>Ӟ当函数运行完q回时进行弹栈操作时必然会发生错误,可能l果q是非常奇怪的Q甚?br>于生程序Core Dump。所以最好是同一个函Cq行跌{?
熟?zhn)汇编的h都知道,E序q行Ӟ有一个寄存器用于保存当前代码所在的内存地址。所以,
jump命o也就是改变了q个寄存器中的倹{于是,你可以?#8220;set $pc”来更改蟩转执?br>的地址。如Q?
set $pc = 0x485
三、生信号量
使用singal命oQ可以生一个信号量l被调试的程序。如Q中断信号Ctrl+C。这非常方便
于程序的调试Q可以在E序q行的Q意位|设|断点,q在该断点用GDB产生一个信号量Q?br>q种_地在某处产生信号非常有利E序的调试?
语法是:signal QUNIX的系l信号量通常??5。所以取g在这个范围?
single命o和shell的kill命o不同Q系l的kill命o发信L被调试程序时Q是由GDB?br>LQ而single命o所发出一信号则是直接发给被调试程序的?
四、强制函数返?
如果你的调试断点在某个函CQƈq有语句没有执行完。你可以使用return命o强制函数
忽略q没有执行的语句q返回?
return
return
使用return命o取消当前函数的执行,q立卌回,如果指定了,那么该表辑ּ的g被认
作函数的q回倹{?
五、强制调用函?
call
表达式中可以一是函敎ͼ以此辑ֈ强制调用函数的目的。ƈ昄函数的返回|如果函数q?br>回值是voidQ那么就不显C?
另一个相似的命o也可以完成这一功能——printQprint后面可以跟表辑ּQ所以也可以用他
来调用函敎ͼprint和call的不同是Q如果函数返回voidQcall则不昄Qprint则显C函数返
回|q把该值存入历史数据中?
在不同语a中用GDB
—————————?
GDB支持下列语言QC, C++, Fortran, PASCAL, Java, Chill, assembly, ?Modula-2。一般说
来,GDB会根据你所调试的程序来定当然的调试语aQ比如:发现文g名后~?#8220;.c”
的,GDB会认为是CE序。文件名后缀?#8220;.C, .cc, .cp, .cpp, .cxx, .c++”的,GDB会认为是
C++E序。而后~?#8220;.f, .F”的,GDB会认为是FortranE序Q还有,后缀为如果是“.s, .S”
的会认ؓ是汇~语a?
也就是说QGDB会根据你所调试的程序的语言Q来讄自己的语a环境Qƈ让GDB的命?br>跟着语言环境的改变而改变。比如一些GDB命o需要用到表辑ּ或变量时Q这些表辑ּ?br>变量的语法,完全是根据当前的语言环境而改变的。例如C/C++中对指针的语法是*pQ而在
Modula-2中则是p^。ƈ且,如果你当前的E序是由几种不同语言一同编译成的,那到在调
试过E中QGDB也能Ҏ(gu)不同的语a自动地切换语a环境。这U跟着语言环境而改变的?br>能,真是体脓(chung)开发h员的一U设计?
下面是几个相关于GDB语言环境的命令:
show language
查看当前的语a环境。如果GDB不能识ؓ你所调试的编E语aQ那么,C语言被认为是?br>认的环境?
info frame
查看当前函数的程序语a?
info source
查看当前文g的程序语a?
如果GDB没有出当前的程序语aQ那么你也可以手动设|当前的E序语言。用set
language命o卛_做到?
当set language命o后什么也不跟的话Q你可以查看GDB所支持的语aU类Q?
(gdb) set language
The currently understood settings are:
local or auto Automatic setting based on source file
c Use the C language
c++ Use the C++ language
asm Use the Asm language
chill Use the Chill language
fortran Use the Fortran language
java Use the Java language
modula-2 Use the Modula-2 language
pascal Use the Pascal language
scheme Use the Scheme language
于是你可以在set language后跟上被列出来的E序语言名,来设|当前的语言环境?
后记
—?
GDB是一个强大的命o行调试工兗大家知道命令行的强大就是在于,其可以Ş成执行序
列,形成脚本。UNIX下的软g全是命o行的Q这l程序开发提代供了极大的便利Q命令行
软g的优势在于,它们可以非常Ҏ(gu)的集成在一P使用几个单的已有工具的命令,可
以做Z个非常强大的功能?
于是UNIX下的软g比Windows下的软g更能有机地结合,各自发挥各自的长处,l合?br>更ؓ强劲的功能。而Windows下的囑Ş软g基本上是各自Q互怸能调用,很不利于
各种软g的相互集成。在q里q不是要和Windows做个什么比较,所?#8220;寸有所长,有
所?#8221;Q图形化工具q是有不如命令行的地斏V(看到q句话时Q希望各位千万再也不要认?br>我就?#8220;鄙视囑Ş界面”Q和我抬杠了 Q?
我是Ҏ(gu)版本?.1.1的GDB所写的q篇文章Q所以可能有些功能已被修改,或是又有?br>为强劲的功能。而且Q我写得非常仓促Q写得比较简略,q且Q其中我已经看到有许多错?br>字了Q我用五W,所以错字让你看不懂Q,所以,我在q里Ҏ(gu)文中的差错表CZ分的歉意?
文中所|列的GDB的功能时Q我只是|列了一些带用的GDB的命令和使用Ҏ(gu)Q其实,
我这里只讲述的功能大U只占GDB所有功能的60%吧,详细的文档,q是h看GDB?br>帮助和用手册吧Q或许,q段旉Q如果我有空Q我再写一GDB的高U用?
我个人非常喜ƢGDB的自动调试的功能Q这个功能真的很强大Q试惻I我在UNIX下写?br>脚本Q让脚本自动~译我的E序Q被自动调试Qƈ把结果报告出来,调试成功Q自动checkin
源码库。一个命令,~译带着调试带着checkinQ多爽啊。只是GDB对自动化调试目前支持
q不是很成熟Q只能实现半自动化,真心期望着GDB的自动化调试功能的成熟?
如果各位对GDB或是别的技术问题有兴趣的话Q欢q和我讨Z。本人目前主要在UNIX
下做产品软g的开发,所以,对UNIX下的软g开发比较熟(zhn),当然Q不单单是技术,对Y
件工E实施,软g设计Q系l分析,目理我也略有心得。欢q大家找我交,QQQ是:
753640QMSN是:haoel@hotmail.comQ?
RelatedEntriesQ?
文g操作 - 10 28, 2003
OSW:12.CVS讄与应?- 10 28, 2003
MySQL AB Acquires Alzato - 10 24, 2003
cvs - 10 24, 2003
使用CVSq行版本理 - 10 23, 2003
value_type& front( ); const value_type& front( ) const;
Returns a reference to the first element at the front of the queue.
L下面CZ代码
queue<int> intqueue;
intqueue.push(1);
intqueue.push(2);
int head = intqueue.front();//int&可以隐式转换为int?
intqueue.pop();//对头元素弹出队?br>cout << head << endl;//输出1Qfront应该q回的是"引用",但pop之后Qؓ什么head的输有效(引用q有效?)Q?br>
}
lock_.UnLock();
}
return instance_;
}
protected:
static CAutoLock lock_ ;
static T* instance_;
};
template <class T>
CAutoLock SingleTon<T>::lock_;
template<class T>
T* SingleTon<T>::instance_;
if(ret != 0)
{
cout<<"query error"<<endl;
cout << mysql_error(conn_ptr) << endl;
}
}
文g I/O 在C++中比烤蛋p简单多了?在这文章里Q我会详l解释ASCII和二q制文g的输入输出的每个l节Q值得注意的是Q所有这些都是用C++完成的?br>
一、ASCII 输出 Z使用下面的方? 你必d含头文g<fstream.h>(译者注Q在标准C++中,已经使用<fstream>取代< fstream.h>Q所有的C++标准头文仉是无后缀的?。这?<iostream.h>的一个扩展集, 提供有缓冲的文g输入输出操作. 事实? <iostream.h> 已经?lt;fstream.h>包含? 所以你不必包含所有这两个文g, 如果你想昑ּ包含他们Q那随便你。我们从文g操作cȝ设计开? 我会讲解如何q行ASCII I/O操作。如果你猜是"fstream," 恭喜你答对了Q?但这文章介l的Ҏ(gu),我们分别使用"ifstream"??"ofstream" 来作输入输出?br> 如果你用q标准控制台?cin"??"cout," 那现在的事情对你来说很简单?我们现在开始讲输出部分Q首先声明一个类对象。ofstream fout; q就可以了,不过你要打开一个文件的? 必须像这栯用ofstream::open()?br> fout.open("output.txt"); 你也可以把文件名作ؓ构造参数来打开一个文? ofstream fout("output.txt"); q是我们使用的方? 因ؓq样创徏和打开一个文件看h更简? Z说一? 如果你要打开的文件不存在Q它会ؓ你创Z? 所以不用担心文件创建的问题. 现在p出到文gQ看h?cout"的操作很像?对不了解控制台输?cout"的h, q里有个例子?br> int num = 150; char name[] = "John Doe"; fout << "Here is a number: " << num << "\n"; fout << "Now here is a string: " << name << "\n"; 现在保存文gQ你必须关闭文gQ或者回写文件缓? 文g关闭之后׃能再操作? 所以只有在你不再操作这个文件的时候才调用它,它会自动保存文g?回写~冲Z在保持文件打开的情况下保存文g, 所以只要有必要׃用它。回写看h像另一ơ输? 然后调用Ҏ(gu)关闭。像q样Q?br> fout << flush; fout.close(); 现在你用文本~辑器打开文gQ内容看h是这P Here is a number: 150 Now here is a string: John Doe 很简单吧! 现在l箋文g输入, 需要一Ҏ(gu)? 所以先认你已l明白了操作,?"<<" ?>>" 比较熟?zhn)? 因ؓ你接下来q要用到他们。l?#8230; 二、ASCII 输入 输入?cin" 很? 和刚刚讨论的输出很? 但你要考虑几g事情。在我们开始复杂的内容之前, 先看一个文本: 12 GameDev 15.45 L This is really awesome! Z打开q个文gQ你必须创徏一个in-stream对象,?像这栗?br> ifstream fin("input.txt"); 现在d前四? 你还记得怎么?<<" 操作W往里插入变量和符号吧Q好,??"<<" (插入)?操作W之后,?>>" (提取) 操作W? 使用Ҏ(gu)是一L. 看这个代码片D? int number; float real; char letter, word[8]; fin >> number; fin >> word; fin >> real; fin >> letter; 也可以把q四行读取文件的代码写ؓ更简单的一行?br> fin >> number >> word >> real >> letter; 它是如何q作的呢? 文g的每个空白之? ">>" 操作W会停止d内容, 直到遇到另一?gt;>操作W? 因ؓ我们d的每一行都被换行符分割开(是空白字W?, ">>" 操作W只把这一行的内容d变量。这是q个代码也能正常工作的原因。但是,可别忘了文g的最后一行?br> This is really awesome! 如果你想把整行读入一个char数组, 我们没办法用">>"?操作W,因ؓ每个单词之间的空|I白字符Q会中止文g的读取。ؓ了验证: char sentence[101]; fin >> sentence; 我们惛_含整个句? "This is really awesome!" 但是因ؓI白, 现在它只包含?This". 很明? 肯定有读取整行的Ҏ(gu), 它就是getline()。这是我们要做的?br> fin.getline(sentence, 100); q是函数参数. W一个参数显然是用来接受的char数组. W二个参数是在遇到换行符之前Q数l允许接受的最大元素数? 现在我们得到了想要的l果Q?#8220;This is really awesome!”?br> 你应该已l知道如何读取和写入ASCII文g了。但我们q不能Ş休,因ؓ二进制文件还在等着我们?br> 三、二q制 输入输出 二进制文件会复杂一? 但还是很单的。首先你要注意我们不再用插入和提取操作W?译者注Q?lt;< ?>> 操作W?. 你可以这么做Q但它不会用二进制方式读写。你必须使用read() 和write() Ҏ(gu)d和写入二q制文g. 创徏一个二q制文g, 看下一行?br> ofstream fout("file.dat", ios::binary); q会以二q制方式打开文g, 而不是默认的ASCII模式。首先从写入文g开始。函数write() 有两个参数?W一个是指向对象的charcd的指? W二个是对象的大(译者注Q字节数Q?Z说明Q看例子?br> int number = 30; fout.write((char *)(&number), sizeof(number)); W一个参数写?(char *)(&number)". q是把一个整型变量{为char *指针。如果你不理解,可以立刻阅C++的书c,如果有必要的话。第二个参数写作"sizeof(number)". sizeof() q回对象大小的字节数. 是q样! 二进制文件最好的地方是可以在一行把一个结构写入文件?如果_你的l构?2个不同的成员?用ASCII?文gQ你不得不每ơ一条的写入所有成员?但二q制文g替你做好了?看这个?br> struct OBJECT { int number; char letter; } obj; obj.number = 15; obj.letter = ‘M’; fout.write((char *)(&obj), sizeof(obj)); q样写入了整个l构! 接下来是输入. 输入也很单,因ؓread()?函数的参数和 write()是完全一L, 使用Ҏ(gu)也相同?br> ifstream fin("file.dat", ios::binary); fin.read((char *)(&obj), sizeof(obj)); 我不多解释用? 因ؓ它和write()是完全相同的。二q制文g比ASCII文g? 但有个缺Ҏ(gu)无法用文本编辑器~辑?接着, 我解释一下ifstream 和ofstream 对象的其 |
使用 <multimap> 库创建重复键兌容器
作者:Danny Kalev
~译QTT 工作?/p>
原文出处Q?a target=_blank>Use multimap to Create Associative Containers with Duplicate Keys
摘要Q?/strong>标准库的 multimap 容器?map 兌容器非常cM——但是,multimap 允许重复键。这个特性?multimap 比想象的要有用得多。本文将对之q行探讨?/td> |
// ? 伪码 multimap <string, string> phonebook; phonebook.insert("Harry","8225687"); // 安?sh)? phonebook.insert("Harry","555123123"); // 单位?sh)? phonebook.insert("Harry"," 2532532532"); // Ud?sh)?/pre>?multimap 中能存储重复键的能力大大地媄响它的接口和使用。那么如何创建非唯一键的兌容器呢?{案是用在 <map> 库中定义?multimap 容器?br>
提出问题
?map 不同Qmultimap 可以包含重复键。这带来一个问题:重蝲下标操作W如何返回相同键的多个关联|以下面的伪码ZQ?/p>string phone=phonebook["Harry];标准?/font>设计者的解决q个问题Ҏ(gu)是从 multimap 中去掉下标操作符。因此,需要用不同的方法来插入和获取元素以及和q行错误处理?br>
插入
假设你需要开发一?DNS 后台E序Q也是 Windows pȝ中的服务E序Q,该程序将 IP 地址映射匚w?URL 丌Ӏ你知道在某些情况下Q相同的 IP 地址要被兌到多?URLs。这?URLs 全都指向相同的站炏V在q种情况下,你应该?multimapQ而不?map。例如:#include <map> #include <string> multimap <string, string> DNS_daemon;?insert() 成员函数而不?a target=_blank>下标操作W?/font>来插入元素。insert()有一?pair cd的参数。在“使用 <map> 库创建关联容?/font>”中我们示范了如何使用 make_pair() 辅助函数来完成此d。你也可以象下面q样使用它:
DNS_daemon.insert(make_pair("213.108.96.7","cppzone.com"));在上面的 insert()调用中,?“213.108.96.7”是键Q?#8220;cppzone.com”是其兌的倹{以后插入的是相同的键,不同的关联|
DNS_daemon.insert(make_pair("213.108.96.7","cppluspluszone.com"));因此QDNS_daemon 包含两个用相同键值的元素。注?multimap::insert() ?map::insert() q回的值是不同的?/p>
typedef pair <const Key, T> value_type; iterator insert(const value_type&); // #1 multimap pair <iterator, bool> insert(const value_type&); // #2 mapmultimap::insert()成员函数q回指向新插入元素的q代指针Q也是 iteratorQmultimap::insert()L能执行成功)。但?map::insert() q回 pair<iterator, bool>Q此?bool DC插入操作是否成功?br>
查找单个?/strong>
?map cMQmultimap 具备两个版本重蝲?find()成员函数Q?/p>iterator find(const key_type& k); const_iterator find(const key_type& k) const;find(k) q回指向W一个与?k 匚w?pair 的P代指针,q就是说Q当你想要检查是否存在至一个与该键兌的值时Q或者只需W一个匹配时Q这个函数最有用。例如:
typedef multimap <string, string> mmss; void func(const mmss & dns) { mmss::const_iterator cit=dns.find("213.108.96.7"); if (cit != dns.end()) cout <<"213.108.96.7 found" <<endl; else cout <<"not found" <<endl; }处理多个兌?/strong>
count(k) 成员函数q回与给定键兌的值得数量。下面的例子报告了有多少个与?“213.108.96.7” 兌的|cout<<dns.count("213.108.96.7") //output: 2 <<" elements associated"<<endl;Z存取 multimap 中的多个|使用 equal_range()、lower_bound()?upper_bound()成员函数Q?br>equal_range(k)Q该函数查找所有与 k 兌的倹{返回P代指针的 pairQ它标记开始和l束范围。下面的例子昄所有与?#8220;213.108.96.7”兌的|
typedef multimap <string, string>::const_iterator CIT; typedef pair<CIT, CIT> Range; Range range=dns.equal_range("213.108.96.7"); for(CIT i=range.first; i!=range.second; ++i) cout << i->second << endl; //output: cpluspluszone.com // cppzone.comlower_bound() ?upper_bound()Qlower_bound(k) 查找W一个与?k 兌的|?upper_bound(k) 是查扄一个键值比 k 大的元素。下面的例子C?upper_bound()来定位第一个其键值大?#8220;213.108.96.7”的元素。通常Q当键是一个字W串Ӟ会有一个词典编U比较:
dns.insert(make_pair("219.108.96.70", "pythonzone.com")); CIT cit=dns.upper_bound("213.108.96.7"); if (cit!=dns.end()) //found anything? cout<<cit->second<<endl; //display: pythonzone.com如果你想昄其后所有的|可以用下面这L循环Q?
// 插入有相同键的多个? dns.insert(make_pair("219.108.96.70","pythonzone.com")); dns.insert(make_pair("219.108.96.70","python-zone.com")); // 获得W一个值的q代指针 CIT cit=dns.upper_bound("213.108.96.7"); // 输出: pythonzone.comQpython-zone.com while(cit!=dns.end()) { cout<<cit->second<<endl; ++cit; }l论
虽然 map ?multimap h相同的接口,光要差别在于重复键Q设计和使用要区别对待。此外,q要注意每个容器?insert()成员函数的细微差别?br>
很多人都使用传统的C
让我们来看一个具体的范例。假设你x一个int转换为string。ؓ了达到这一目的Q你必须遵@如下的步骤:
1. 建立一个stringstream对象Q?/span>
2.使用操作W?/span><<插入int数据Q?/p>
3.使用操作W?/span>>>抽取前面插入到的数据C个string对象中?/p>
以下代码行演CZq些步骤Q?/p>
int main(int argc, char *argv[]) h意我们没有用一个简z的cast操作或一个模式标志来实现stringstream转换。操作符<<?gt;>会自动地删除原始数据的类型和目标数据Qƈ自动而安全地执行需要的转换?/p>
int main(int argc, char *argv[]) 如果你想通过使用同一stringstream对象实现多种cd的{换,h意在每一ơ{换之后都必须调用clear()成员函数Q例如:
int main(int argc, char *argv[])
cout << "n:\t" << n << endl; //print 456 事实上,stream对象可以接收多种cd输入的特点给我们带来一个好处,可以intQchar*{不同类型的输入同时导入C个stream对象Q再通过该stream对象导出一个新倹{?/p>
int main(int argc, char *argv[])
cout << "ip:\t" << ip << endl; //print " 218.192.160.228"
Qi nclude <iostream>
Qi nclude <stdlib.h>
Qi nclude <string>
Qi nclude <sstream>
using namespace std;
{
std::stringstream stream;
std::string result;
int num = 1000;
stream << num; //intcd数据插入stream对象?br /> stream >> result; //取出之前插入的数?br /> cout << "num:\t" << num << endl;
cout << "result:\t" << result << endl; //打印 "1000"
system("PAUSE");
return 0;
}
Qi nclude <stdlib.h>
Qi nclude <string>
Qi nclude <sstream>
using namespace std;
{
std::stringstream stream;
char result[12] = {'\0'};
stream << 1234; //insert int to stream
stream >> result; //extract previously inserted value
cout << result << endl; // print "1234"
system("PAUSE");
return 0;
}
Qi nclude <stdlib.h>
Qi nclude <string>
Qi nclude <sstream>
using namespace std;
{
std::stringstream stream;
int n, m;
stream<< "456"; //insert string
stream >> n; //extract to int
stream.clear(); //reset stream before another conversion
stream<< true; //insert bool value
stream >> m; //extract to int
cout << "m:\t" << m << endl; //print 1
system("PAUSE");
return 0;
}
Qi nclude <iostream>
Qi nclude <stdlib.h>
Qi nclude <string>
Qi nclude <sstream>
using namespace std;
{
std::stringstream stream;
char ip[16];
stream << 218; //insert int
stream << "."; //insert string
stream << 192; //insert int
stream << "."; //insert string
stream << 160; //insert int
stream << "."; //insert string
stream << 228; //insert int
stream >> ip;
system("PAUSE");
return 0;
]]>