源程序:
#include "apue.h"
#include <fcntl.h>
int
main(int argc, char *argv[])
{
int val;
if (argc != 2)
err_quit("usage: a.out <descriptor#>");
if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
err_sys("fcntl error for fd %d", atoi(argv[1]));
switch (val & O_ACCMODE) {
case O_RDONLY:
printf("read only");
break;
case O_WRONLY:
printf("write only");
break;
case O_RDWR:
printf("read write");
break;
default:
err_dump("unknown access mode");
}
if (val & O_APPEND)
printf(", append");
if (val & O_NONBLOCK)
printf(", nonblocking");
if (val & O_SYNC)
printf(", synchronous writes");
#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
if (val & O_FSYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}
程序运行结果:(如何运行该书实例代码 参见
APUE.3e 安装(基于ubuntu12.0.4) )
root@ubuntu:/home/yuccess/shiyan/apue.3e/fileio# ./fileflags 0 < /dev/tty
read only
root@ubuntu:/home/yuccess/shiyan/apue.3e/fileio# ./fileflags 1 > temp.foo
root@ubuntu:/home/yuccess/shiyan/apue.3e/fileio# cat temp.foo
write only
root@ubuntu:/home/yuccess/shiyan/apue.3e/fileio# ./fileflags 2 2>>temp.foo
write only, append
root@ubuntu:/home/yuccess/shiyan/apue.3e/fileio# ./fileflags 5 5<>temp.foo
read write
问题1:./fileflags 0 < /dev/tty 什么意思?
知识点重定向(讲解重定向比较好的文章)
< /dev/tty 的意思就是将标准输入重定向为文件tty
0是main()第二个参数(在问题2中讲解)
第一个参数是./fileflags
问题2: ./fileflags 2 2>>temp.foo怎么解释。
有了重定向的知识后,我们知道了2>>temp.foo的意识就是 将一个标准错误输出重定向到一个文件或设备 追加到原来的文件
那么 中间的那个2 又是什么意思?从源程序说起
main(int argc, char *argv[]) main函数参数argv此时为什么?
可以用print()将argv打印出来,不过这样的话就得重新编译了。这时候采用GDB调试的方法,来查看argv。
step1:在终端输入gcc fileflags.c -g -o fileflags -l apue
step2:输入 gdb fileflags
step3:进入gdb后输入调试代码:
(gdb) l -->显示代码
(gdb) b -->设置断点
(gdb) r 2 2>>temp.foo -->run
(gdb) p argv[1] --> 显示结果为 $2 = 0xbffff565 "2"
(gdb) p *argv@2 -->显示数组里的前两个结果 $6 = {0xbffff537 "/home/yuccess/shiyan/apue.3e/fileio/fileflags", 0xbffff565 "2"}
至此我们gdb调试完毕,可以发现 2 是main的第二个参数,而 2>>temp.foo表示将标准输出重定向到temp.foo上(类似于 < /dev/tty),不是一个参数,至于为什么不太清清楚。
感受:gdb调试全键盘的操作,比vs2013、xcode神马的爽爆了啊!
附gdb调试常用命令:
命令 | 描述 |
---|---|
backtrace(或bt) | 查看各级函数调用及参数 |
finish | 连续运行到当前函数返回为止,然后停下来等待命令 |
frame(或f) 帧编号 | 选择栈帧 |
info(或i) locals | 查看当前栈帧局部变量的值 |
list(或l) | 列出源代码,接着上次的位置往下列,每次列10行 |
list 行号 | 列出从第几行开始的源代码 |
list 函数名 | 列出某个函数的源代码 |
next(或n) | 执行下一行语句 |
print(或p) | 打印表达式的值,通过表达式可以修改变量的值或者调用函数 |
quit(或q) | 退出gdb 调试环境 |
set var | 修改变量的值 |
start | 开始执行程序,停在main 函数第一行语句前面等待命令 |
step(或s) | 执行下一行语句,如果有函数调用则进入到函数中 |
在gdb中,和调试步进相关的命令主要有如下几条:
-
continue 继续运行程序直到下一个断点(类似于VS里的F5)
-
next 逐过程步进,不会进入子函数(类似VS里的F10)
-
setp 逐语句步进,会进入子函数(类似VS里的F11)
-
until 运行至当前语句块结束
-
finish 运行至函数结束并跳出,并打印函数的返回值(类似VS的Shift+F11)
问题3:下面这句 话的解释
if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
首先fcntl()函数的意思是改变/返回一个已经打开文件的属性。
参数F_GETFL说明,该函数要返回文件(第一个参数)的状态标识。
可以调试查看val的结果,如果想显示宏O_ACCMODE的值的话,需要在终端这样输入:gcc -gdwarf-2 -g3 fileflags.c -l apue -o fileflags
具体细枝末节请参阅APUE 3.14小节
总结:至此已经基本完全理解了该实例,学习了重定向,GDB调试,fcntl等知识,通过调试实践APUE上面的知识,相信对初学linux编程的童鞋会有帮助。
接下来继续啃APUE。