使用GDB调试程序使用手记
gdb是调试应用程序的一个命令行下的工具。用了用,下面是心得:
以调试processtest可执行文件为例子。
1) gdb processtest
2) 设置一个断点,不然程序一下子就执行完了,什么也调试不成。Break 5,表明断点在第5行。删除断点用clear 5即可。
3) 键入run,执行开始,并在第5行停止。
4) 下面就可以用很多命令了。
l "print <symbol>"显示一个符号。
l "whatis <symbol>"显示符号类型。
l "list"显示源代码的下10行。
l "list <symbol>"显示符号类型的源代码。
l "list-"显示最后10行代码。
l "info registers"显示所有的注册。
l "disassemble"为分解器。
l "where"显示调用堆栈。
l "up"为上升的堆栈结构。
l "down"为下降的堆栈结构。
l "display <symbol>"为程序停止时显示一个符号。
文件方面的操作
open函数有两个形式.其中pathname是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面).flags可以去下面的一个值或者是几个值的组合.
O_RDONLY:以只读的方式打开文件.
O_WRONLY:以只写的方式打开文件.
O_RDWR:以读写的方式打开文件.
O_APPEND:以追加的方式打开文件.
O_CREAT:创建一个文件.
O_EXEC:如果使用了O_CREAT而且文件已经存在,就会发生一个错误.
O_NOBLOCK:以非阻塞的方式打开一个文件.
O_TRUNC:如果文件已经存在,则删除文件的内容.
前面三个标志只能使用任意的一个.如果使用了O_CREATE标志,那么我们要使用open的第二种形式.还要指定mode标志,用来表示文件的访问权限.mode可以是以下情况的组合.
-----------------------------------------------------------------
S_IRUSR 用户可以读 S_IWUSR 用户可以写
S_IXUSR 用户可以执行 S_IRWXU 用户可以读写执行
-----------------------------------------------------------------
S_IRGRP 组可以读 S_IWGRP 组可以写
S_IXGRP 组可以执行 S_IRWXG 组可以读写执行
-----------------------------------------------------------------
S_IROTH 其他人可以读 S_IWOTH 其他人可以写
S_IXOTH 其他人可以执行 S_IRWXO 其他人可以读写执行
-----------------------------------------------------------------
S_ISUID 设置用户执行ID S_ISGID 设置组的执行ID
-----------------------------------------------------------------
我们也可以用数字来代表各个位的标志.Linux总共用5个数字来表示文件的各种权限.
00000.第一位表示设置用户ID.第二位表示设置组ID,第三位表示用户自己的权限位,第四位表示组的权限,最后一位表示其他人的权限.
每个数字可以取1(执行权限),2(写权限),4(读权限),0(什么也没有)或者是这几个值的和.
比如我们要创建一个用户读写执行,组没有权限,其他人读执行的文件.设置用户ID位那么我们可以使用的模式是--1(设置用户ID)0(组没有设置)7(1+2+4)0(没有权限,使用缺省)5(1+4)即10705:
open("temp",O_CREAT,10705);
如果我们打开文件成功,open会返回一个文件描述符.我们以后对文件的所有操作就可以对这个文件描述符进行操作了.
Copy文件的例子代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#define BUFFER_SIZE 1024
int main(int argc , char **argv)
{
int from_fd;
int to_fd;
int bytes_read;
int bytes_write;
char buffer[BUFFER_SIZE];
char * ptr;
if(argc != 3){
fprintf(stderr,"Usage:%s fromfile tofile\n\a",argv[0]);
exit(1);
}
if((from_fd = open(argv[1],O_RDONLY)) == -1){
fprintf(stderr,"Open %s Error:%s\n",argv[1],strerror(errno));
exit(1);
}
//create destination file
if((to_fd = open(argv[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR)) == -1){
fprintf(stderr,"Open %s Error:%s \n",argv[2],strerror(errno));
exit(1);
}
//this is a segment of classical codes about copy's operation.
while(bytes_read = read(from_fd,buffer,BUFFER_SIZE)){
//error appeared
if((bytes_read == -1) && (errno != EINTR))
break;
else if(bytes_read > 0){
ptr = buffer;
while(bytes_write = write(to_fd,ptr,bytes_read)){
//error appeared
if((bytes_write == -1) && (errno != EINTR))
break;
//write is all of read buffer
else if(bytes_write == bytes_read)
break;
//write is a part of read buffer, continue write.
else if(bytes_write > 0){
ptr += bytes_write;
bytes_read -= bytes_write;
}
}
//error appeared when writing.
if(bytes_write == -1)
break;
}
}
return 0;
}
文件的属性
文件的属性包括:访问权限,时间,大小等等。
如果判断文件是否可以进行某种操作,可以用Access函数。
其它属性使用stat和fstat来获得。
当前工作路径用getcwd函数获得。
还有很多常用的函数,比如:
mkdir
opendir
dirent
rewinddir
telldir
seekdir
closedir
下面例子演示各种文件操作。
//Get specific file's attrib. The file is a file or directory.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <dirent.h>
static int get_file_size_time(const char * filename)
{
struct stat statbuf;
if(stat(filename , &statbuf) == -1){
printf("Get stat on %s Error : %s\n",filename,strerror(errno));
return (-1);
}
if(S_ISDIR(statbuf.st_mode))
return(1);
if(S_ISREG(statbuf.st_mode))
printf("%s size: %ld bytes \t modified at %s",filename,statbuf.st_size,ctime(&statbuf.st_mtime));
return 0;
}
int main(int argc , char **argv)
{
DIR * dirp;
struct dirent * direntp;
int stats;
if(argc != 2){
printf("Usage: %s filename \n\a",argv[0]);
exit(1);
}
stats = get_file_size_time(argv[1]);
if(stats == 0 || stats == -1)
exit(1);
if((dirp = opendir(argv[1])) == NULL){
printf("Open Directioy %s Error:%s \n",argv[1],strerror(errno));
exit(1);
}
while((direntp = readdir(dirp)) != NULL){
if(get_file_size_time(direntp->d_name))
closedir(dirp);
}
return 0;
}
管道:
功能上,管道提供了一种在各个进程间大量传输信息的通道。能够有效完成数据共享和信息交换。
本质上,管道是一个特殊的文件。
分为PIPE(无名字)和FIFO(有名)两种。
与其它通信机制相比,如信号(Signal),消息传递(Message Passing)、共享内存比,有以下突出特点:
1) 方式简单,不需要考虑每次传送的长度。
2) 接受进程按需提取信息。
3) 接收和发送进程都能了解对方进程是否存在,因此相互协调工作。
无名管道:
1) 不占用文件目录项,没有文件路径名
2) 只能用于连接具有共同祖先的进程。
3) 依附进程临时存在,并不永久存在于系统中。
有名管道:
1) 永久性机构,用MKNOD命令创建。
2) 除非刻意删除,一直存在。
时间编程
time函数,用于返回1970年1月1日0点以来的秒数。
Ctime函数将上面数字转换成字符串。
使用Gettimeofday函数可以进行效率分析,下面是例子代码:
#include <stdio.h>
#include <math.h>
#include <sys/time.h>
void function()
{
unsigned int i , j;
double y;
for(i = 0;i < 1000;i ++)
for(j = 0;j < 1000;j ++)
y = sin((double) i );
}
void main(void)
{
struct timeval tpstart;
struct timeval tpend;
float timeuse;
gettimeofday(&tpstart,NULL);
function();
gettimeofday(&tpend,NULL);
timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec)
+ (tpend.tv_usec - tpstart.tv_usec);
timeuse /= 1000000;
printf("Used Time:%f \n",timeuse);
exit(0);
}
如果需要使用时间间隔,则需要用到另外一些函数。
Getitimer
Setitimer
Which决定使用计时器中的哪一个。
下面是一个类似Windows下的Settimer事件的例子,每两秒钟有一个输出。
#include <stdio.h>
#include <math.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#define PROMPT "2 seconds passed \n\a"
char * prompt = PROMPT;
unsigned int len;
void prompt_info(int signo)
{
write(STDERR_FILENO,prompt,len);
}
void init_sigaction(void)
{
struct sigaction act;
act.sa_handler = prompt_info;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGPROF,&act,NULL);
}
void init_time()
{
struct itimerval value;
value.it_value.tv_sec = 2;
value.it_value.tv_usec = 0;
value.it_interval = value.it_value;
setitimer(ITIMER_PROF,&value,NULL);
}
void main(void)
{
len = strlen(prompt);
init_sigaction();
init_time();
while(1);
exit(0);
}
= 未完待续 =