#include "stdio.h" int main() { while(1) { printf("my tooth is fucking aching again!!!\n"); } return 0; }
Archive for 2010 年 6 月
try it,please
28 6 月, 2010把错误捕获函数放入error.h
22 6 月, 2010之前我写过一个关于linux下C编程中错误捕获函数的文章,即我们可以自己编写一个函数来捕获一些错误,让程序员处理错误的时候更简单。如果将这个函数放入error.h头文件中,那么以后就可以直接调用了。本文便是和大家一起讨论如何将自己编写的错误捕获函数放入头文件error.h中。
头文件放在/usr/include目录下,进入这个目录,然后用vi编辑器打开error.h文件。要添加的两个函数如下:
void my_err1(int error) { printf("error: %s with errno: %d\n",strerror(error),error); exit(1); } void my_err2(const char* err_string,int line,int error) { printf("error: line:%d %s():%s with errno:%d\n",line,err_string,strerror(error),error); exit(1); }
将上述两函数添加至文件末尾。由于strerror()函数涉及到头文件string.h,所以在已打开的error.h文件中还得添加string.h头文件。具体添加位置可参考下面:
20 #ifndef _ERROR_H 21 #define _ERROR_H 1 22 23 #include "features.h" 24 25 //personal addition 26 #include "string.h" 27 //personal addition end 28 29 __BEGIN_DECLS 30 59 //personal addition 60 //brief function 61 void my_err1(int error) 62 { 63 printf("error: %s with errno: %d\n",strerror(error),error); 64 exit(1); 65 } 66 67 //detailed function 68 void my_err2(const char* err_string,int line,int error) 69 { 70 printf("error: line:%d %s():%s with errno:%d\n",line,err_string,strerror(error),error); 71 exit(1); 72 } 73 //persoanl addition end 74 __END_DECLS 75 76 #endif /* error.h */
其中my_err1和my_err2显示的错误信息稍有不同。添加好后就可以保存了。但是现在问题来了:按照平时我们的保存方法:wq保存时,会提示:E45: 已设定选项 ‘readonly’ (请加 ! 强制执行)。这是因为头文件属于系统文件,linux为了安全起见,不允许普通用户对其进行修改。我们可以用ls -l查看其属性:
edsionte@edsionte-laptop:/usr/include$ ls -l error.h -rw-r--r-- 1 root root 2557 2010-06-23 12:11 error.h
从上面的文件存取权限可以看出,root用户可以对其读写,root所在的root组可对其读,其他组用户只可对其读。现在我们更改这个文件的权限,让非root用户可对其修改。
edsionte@edsionte-laptop:/usr/include$ sudo chmod 777 error.h [sudo] password for edsionte: edsionte@edsionte-laptop:/usr/include$ ls -l error.h -rwxrwxrwx 1 root root 2557 2010-06-23 12:11 error.h
修改好权限后,就可以用上面的方法对error.h文件进行修改并保存。
下面进行测试:
测试源码如下。
#include “errno.h” #include “fcntl.h“ #include "unistd.h” #include "stdlib.h“ #include "stdio.h” #include ”sys/types.h“ #include “sys/stat.h” #include ”string.h“ #include “error.h” int main() { int fd; if((fd=open("example_test.c",O_CREAT|O_EXCL,S_IRUSR|S_IWUSR))==-1) { my_err1(errno); // my_err2("open",__LINE__,errno); } close(fd); return 0; } }
首先测试my_err1,结果如下:
edsionte@edsionte-laptop:~/code$ ./my_error error: File exists with errno: 17
然后将my_err1注释掉,测试my_err2,结果如下:
edsionte@edsionte-laptop:~/code$ ./my_error error: line:17 open():File exists with errno:17
结果和前面介绍捕获函数时的测试结果一样。你以为现在就结束了吗?当然没有,我们要把error.h头文件的权限修改成原样。
edsionte@edsionte-laptop:/usr/include$ sudo chmod 644 error.h [sudo] password for edsionte: edsionte@edsionte-laptop:/usr/include$ ls -l error.h -rw-r--r-- 1 root root 2557 2010-06-23 12:50 error.h
大功告成。
实现自己ls命令(下)
21 6 月, 2010在本文上部分中,主要陈述my_ls.c的大致结构,本文主要来分析my_ls中主函数是如何实现的。
(1)进入main函数。首先对命令行参数进行解析,即提取命令行参数中‘-’后的选项。用户的输入有多样性,如ls -l -a;ls -la。我们用两层循环类来解析参数,外层循环对argv[]数组中的元素依次进行内层循环的解析,二层循环对以‘-’为首的字符串进行选项提取,并把每个选项存于param[]数组当中,用num来记下‘-’的数目,以备后用。而命令行参数中的总选项数目则用j计数。实现代码如下:
j=0; num=0; for(i=1;i<\argc;i++) { if(argv[i][0]=='-') { for(k=1;k<\strlen(argv[i]);k++) { param[j++]=argv[i][k]; } num++;//count the number of '-' } }
接下来,我们来检查刚刚提取的选项是否合法。本程序我们只支持选项-l和-a,因此如果我们增添其他选项,只要适当添加代码即可。并且我们用或运算记录参数,以备后用。最后为选项数组的末尾元素赋‘\0’。
//check the argument because of only supporting -a and -l for(i=0;i<\j;i++) { if(param[i]=='a') { flag_param|=PARAM_A; continue; } else if(param[i]=='l') { flag_param|=PARAM_L; continue; } else { printf("error:my_ls invalid option -%c\n",param[i]); exit(1); } } param[j]='\0';
由上面我们所知num记录的是参数中‘-’的数量,因此如果num+1==argc,那说明用户所输入的命令行参数不包含目录或文件名。只是显示当前目录下的文件。因为这是我们必须自动将path赋值为当前目录。为了使其称为一个字符串,必须在末尾加‘\0’。然后进入display_dir函数。实现代码如下:
//print the information of current directory if the command without the name of target file and current directory if((num+1)==argc) { strcpy(path,"./"); path[2]='\0'; display_dir(flag_param,path); return 0; }
如果命令行参数包含目录或者文件名,那么我们要检查其合法性(参数中的目录或者文件是否存在)。这里我们利用stat族函数来获取文件的属性,实现上述功能。stat族函数通常有两个参数:文件路径/文件描述符,struct stat *buf类型的结构体。如果操作成功,那么buf将保存文件的属性。若合法,利用宏S_ISDIR(buf.st_mode);判断此文件是否为目录文件。若为目录文件则进入display_dir函数,否则进入display函数。通常情况,display_dir函数是获取path目录下所有文件的完整路径名,在使每个文件执行dsiplay函数。因此如果参数中是指定的文件名,则可绕过display_dir函数,直接进入display函数。
i=1; do { //the current argument doesn't comprise the target file name and dirctory name if(argv[i][0]=='-') { i++; continue; } else { strcpy(path,argv[i]); //detect if the "path" exsit if(stat(path,&buf)==-1) { my_err("stat",errno,__LINE__); } //detect the "path" is a file or a directory if(S_ISDIR(buf.st_mode)) { //directory //detect if the last character of the "path" is '/' if(path[strlen(path)-1]=='/') { path[strlen(path)]=='\0'; } else { path[strlen(path)]='/'; path[strlen(path)]='\0'; } display_dir(flag_param,path); i++; } else { //file display(flag_param,path); i++; } } }while(i<\argc);
实现自己的ls命令(上)
19 6 月, 2010如果你跟我一样是linux下C编程的初学者,那么动手实现一些linux命令是十分有必要的。本文为你所描述的是常用ls命令。ls命令有众多选项,本文中所描述的my_ls.c程序仅实现了-l和-a选项。
ls命令加入-l选项可以使每个文件单独成一行,并且显示文件的属性。比如:
edsionte@edsionte-laptop:~/code$ ls -l 总用量 232 -rwxr-xr-x 1 edsionte edsionte 9530 2010-06-18 11:26 error -rw-r--r-- 1 edsionte edsionte 756 2010-06-19 14:39 error.c -rw-r--r-- 1 edsionte edsionte 755 2010-06-18 11:32 error.c~ -rw------- 1 edsionte edsionte 0 2010-06-16 12:40 example_62.c
ls命令加入-a选项可以显示隐藏文件。linux中隐藏文件是以 . 开头的。比如:
edsionte@edsionte-laptop:~/code$ ls -a . example_65.c my_cdvc my_mv .. example_68_1.c my_cdvc.c my_mv.c
.表示当前目录,..表示当前目录的父目录。
当然这两个选项可以同时使用,比如:
edsionte@edsionte-laptop:~/code$ ls -al 总用量 240 drwxr-xr-x 3 edsionte edsionte 4096 2010-06-20 12:10 . drwxr-xr-x 46 edsionte edsionte 4096 2010-06-20 12:10 .. -rwxr-xr-x 1 edsionte edsionte 9530 2010-06-18 11:26 error -rw-r--r-- 1 edsionte edsionte 756 2010-06-19 14:39 error.c -rw-r--r-- 1 edsionte edsionte 755 2010-06-18 11:32 error.c~ -rw------- 1 edsionte edsionte 0 2010-06-16 12:40 example_62.c edsionte@edsionte-laptop:~/code$ ls -l -a 总用量 240 drwxr-xr-x 3 edsionte edsionte 4096 2010-06-20 12:10 . drwxr-xr-x 46 edsionte edsionte 4096 2010-06-20 12:10 .. -rwxr-xr-x 1 edsionte edsionte 9530 2010-06-18 11:26 error -rw-r--r-- 1 edsionte edsionte 756 2010-06-19 14:39 error.c
本文所述的my_ls.c程序就要实现这种功能。在了解本程序中所有函数之前,请先看一下本程序的流程图:点这里(本blog上传图片有点问题,正在解决中……)。
现在对本程序中的各个函数做以大致说明。
(1)void my_err(const char*,int,int);和void my_err2(const char*,int);
错误捕获函数。详细实现过程请点这里。
(2)void display_dir(int flag_param,char*path);
如果命令中含有目录,则进入此函数。此函数将获取path目录下的文件总数以及所有文件名(包括隐藏文件)。流程图点这里。
(3)void display(int flag,char*pathname);
pathname是一个文件的完整路径名,本函数首先从完整的路径名中解析出文件名,再根据flag进入不同的函数。流程图点这里。
(4)void display_single(char*);
如果参数中不含任何选项或者仅含-a,则进入此函数。本函数直接显示出目录下的所有文件名,并且实现文件名左对齐。
(5)void display_attribute(struct stat,char*);
如果命令中含有-l则进入本函数,显示出文件的各种属性。
在本文的上班部分中主要为您理清本程序的大体结构,在下半部分中将详细分析源代码。
linux下C编程错误捕获函数
17 6 月, 2010本文中的错误是指在代码编译完全正确程序可运行的情况下,因为没有成功调用程序中的某些系统调用函数而产生的错误。往往这些系统调用函数通过返回值(比如1,0,-1)来说明其是否调用成功,而程序员需要知道详细的错误信息,因此自建错误捕获函数很有必要。
(1)errno和strerror()
errno它是一个整形的错误代码。当发生错误的时候,系统自动将错误代码赋给errno。使用下面的方法可以获得具体的错误描述:
void my_err(int error) { printf("error: %s with errno: %d\n",strerror(error),error); exit(1); } int main() { .............. my_err(errno); .............. }
其中char *strerror(int errnum);是通过errnum来获取错误描述,errnum即所传递的errno。该函数末尾的exit(1)使得程序发生错误时退出。但应该包含库函数stdlib.h。
下面进行测试,测试程序(源代码在本文末尾。)使用open()函数创建文件,因为要创建的文件已存在,而且使用了O_EXCL参数,因此open()会产生错误。结果如下:
edsionte@edsionte-laptop:~/code$ ./error error: File exists with errno: 17
该方法可以详细显示错误信息以及错误代码。但不能显示错误出现的行数。
(2)perror()
其函数原型为:void perror(const char *s)。s一般是函数名。该函数会先将函数名打印出来,然后再打印出错误信息。错误信息与errno相对应。第二个参数__LINE__是一个宏,表示当前的行数。使用方法:
void my_err2(const char* err_string,int line) { fprintf(stderr,"error: line:%d ",line); perror(err_string); exit(1); } } int main() { ................. my_err2("open",__LINE__); ................ }
测试结果如下:
edsionte@edsionte-laptop:~/code$ ./error error: line:29 open: File exists }
该方法可以显示错误信息以及错误出现的行数。
以上方法是在《linux C编程》中常用的方法,我适当的作了小调整。现在将这两种方法结合起来:
void my_err3(const char* err_string,int line,int error) { printf("error: line:%d %s():%s with errno:%d\n",line,err_string,strerror(error),error); exit(1); } int main() { ................ my_err3("open",__LINE__,errno); ................ }
测试结果如下:
edsionte@edsionte-laptop:~/code$ ./error error: line:30 open():File exists with errno:17
这样就可以显示错误代码,错误描述,错误出现的行数以及出现错误的函数。对于和我一样的新手来说,这里特别要注意的是宏__LINE__前后的那个横线是两个连续的下划线,而不是_LINE_,否则会出现错误。
源代码如下:
说明:本程序只作测试用,为了同时显示三种错误捕获函数的信息,因此屏蔽了每个函数的exit(1)。另外本文头文件函数用“”是因为显示问题,没有什么特别意义。
#include "errno.h" #include "fcntl.h" #include "unistd.h" #include "stdlib.h" #include "stdio.h #include "sys/types.h" #include "sys/stat.h" #include "string.h" void my_err(int error) { printf("error: %s with errno: %d\n",strerror(error),error); // exit(1); } void my_err2(const char* err_string,int line) { fprintf(stderr,"error: line:%d ",line); perror(err_string); // exit(1); } void my_err3(const char* err_string,int line,int error) { printf("error: line:%d %s():%s with errno:%d\n",line,err_string,strerror(error),error); // exit(1); } int main() { int fd; if((fd=open("example_test.c",O_CREAT|O_EXCL,S_IRUSR|S_IWUSR))==-1) { my_err(errno); my_err2("open",__LINE__); my_err3("open",__LINE__,errno); } close(fd); return 0; }