命令行参数的误解
命令行参数的误解
前言
我们都知道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 ↩