命令行参数的误解
命令行参数的误解
前言
我们都知道C语言中允许main函数拥有0个或2个参数,但也存在部分操作系统向程序传入更多的参数,还有部分实现中对标准进行扩展,允许main函数拥有更多的参数.命令行参数作为main函数的两个参数被传递给程序,这两个参数通常被命名为int argc,char **argv,其中argc为参数的数量,argv为一个指向内含 argc + 1个 char 类型指针 的指针数组.
但仅用这段话进行描述可能难以对命令行参数有一个正确的认识,这种描述可能对命令行参数的理解不利.
我们先来分析一个程序.
1 | /* ShowCommandLineArgument.c */ |
在笔者的电脑中,该文件被存储在/home/admin/blog/ShowCommandLineArgument.c,输入命令 gcc ShowCommandLineArgument.c 进行编译,得到a.out,并以cd && ./blog/a.out -f ~/bolg/test1.md >./blog/test2.md /home/admin/blog/test3.md ./blog/test4.md执行该程序.
请思考,该程序会输出什么内容?你是否认为程序的输出为
1 | argc:6 |
什么?你说没看到输出?请认真查看笔者输入的指令,其中包括了
>./blog/test2.md 意味把 a.out 的 标准输出 重定向至文件./blog/test2.md .所以笔者使用 cat >./blog/test2.md 查看输出的内容,该程序在笔者的设备上的输出为:1 | argc:5 |
是不是和你的预期不尽相同,请听笔者逐一解释.
常见误区
误区1—-「认为 argv[0] 存储文件名」
实际上,argv[0] 会存储调用的指令中的第一个字符串,而不是文件名,strcmp(argv[0],__FILE__)并不总为0.
误区2—-「认为命令行参数总是被原样传递」
在上面的例子中可以发现,相对路径 ~/blog/test1.md 作为命令行参数传给程序,程序收到的实际上是文件的绝对路径 /home/admin/blog/test3.md .
但同为相对路径的./blog/a.out和./blog/test4.md却可以正常传递给程序,而不被转换为绝对路径.
其他的相对路径写法是否能被正常传递?笔者在此使用由 ShowCommandLineArgument.c 编译得到的 a.out 文件继续测试.使用的指令为 ~/blog/a.out ./test/../blog/test1.md ../test2.md ~admin/blog/test3.md 由这两次测试,笔者大胆猜测只有以 ~ 开头的相对路径会被转换为绝对路径 然后才传递给程序.
1 | argc:4 |
为什么要这么做呢?
请分析笔者的这个程序.
1 |
|
笔者用cd && ./blog/a.out调用该程序编译得到的可执行文件,得到的输出为:
1 | 1Success |
我们可以惊讶的发现只有第一次成功的打开了文件,其他4次操作全部报错.当然,其中第五次打开文件的操作失败是理所当然的,因为确实没有这个文件存在.笔者复制该可执行文件至~/test/a.out后重新执行该程序即发现,第5次文件打开操作成功了.
1 | path1: No such file or directory |
这说明:fopen()无法识别以~开头的相对路径,也体现了命令行参数在传递过程中,转换以~开头的相对路径为绝对路径的必要性.
误区3—「认为重定向是命令行参数」
重定向虽然也在命令行参数的位置,但和命令行参数具有本质的区别.
实践说明重定向指令不会被当中命令行参数传递给程序.
在开发中应该小心,防止误认,也需防止命令行参数中出现相关符号被系统当做重定向指令,导致命令行参数传递错误.
测试环境
OS: Arch Linux
Kernel: x86_64 Linux 5.8.14-arch1-1
参考书籍
1. Stephen Prata.C Primer Plus[M].第六版.姜佑,译.北京:人民邮电出版社 ↩
2. Kenneth.A.Reek.C和指针[M].徐波,译.北京:人民邮电出版社.2008 ↩