使用'__progname'代替argv[0]

18
在我工作的C / Unix环境中,我看到一些开发人员在使用信息消息时使用__progname而不是argv [0]。 这样做有什么优势吗? __prognameargv [0]之间有什么区别? 它是否可移植?
7个回答

19

__progname 不是标准的,因此不具备可移植性,请使用 argv[0]。我猜想 __progname 可以查找一个字符串资源来获取名称,这并不依赖于您运行它的文件名。但是,argv[0] 将为您提供实际运行的名称,我认为这更有用。


5
考虑:execl("/bin/sh","hot potatoes","-c","echo $ 0-嗨",(char *)0); 运行正常; argv [0]为“ hot potatoes” ;回显“ hot potatoes- Hi”。 这与运行的可执行文件的名称无关。 - Jonathan Leffler
2
尽管之前的评论 - 我同意argv [0]更具可移植性。只有少数程序会像那样混淆argv [0] - 但是任何攻击者都可以这样做。在基于argv [0]做出关键决策时要小心。 - Jonathan Leffler

9
使用__progname可以让您在保留程序名称的同时更改argv[]数组的内容。一些常见的工具,如getopt()在处理参数时会修改argv[]
为了可移植性,您可以在程序启动时将argv[0]复制到自己的progname缓冲区中。

2
GNU getopt() 会修改 argv;而非 GNU 版本通常不会这样做。 - Jonathan Leffler
4
@Jonathan:是的,感谢你澄清。我意识到我已经坚持在一个平台上太久了。(抱歉。) - Adam Liss

6

此外,还有一个GNU扩展,可以在不手动保存程序调用名称的情况下从main()之外访问它。然而,手动保存可能更好,这样就可以使其具有可移植性,而不是依赖于GNU扩展。尽管如此,在此提供一段可用文档的摘录。

来自在线GNU C库手册(今天访问):

“许多不从终端读取输入的程序都设计为在任何系统调用失败时退出。按照惯例,这样的程序的错误消息应该以程序的名称开头,不包括目录。您可以在变量program_invocation_short_name中找到该名称;完整的文件名存储在变量program_invocation_name中。

  • 变量:char * program_invocation_name 此变量的值是用于调用当前进程中运行的程序的名称。它与argv[0]相同。请注意,这不一定是有用的文件名;通常它不包含目录名称。

  • 变量:char * program_invocation_short_name 此变量的值是用于调用当前进程中运行的程序的名称,其中删除了目录名称。(也就是说,它与program_invocation_name相同,减去最后一个斜杠之前的所有内容(如果有的话)。

库初始化代码在调用main之前设置这两个变量。

可移植性注意事项:这两个变量是GNU扩展。如果您希望您的程序能够与非GNU库一起使用,则必须在main中保存argv[0]的值,然后自己剥离目录名称。我们添加了这些扩展,以便编写不需要来自main的显式协作的自包含错误报告子例程成为可能。”


5
我看到argv[0]存在至少两个潜在问题。
首先,如果execve()的调用方不够谨慎或者恶意,argv[0]或者argv本身可能为空。调用execve("foobar", NULL, NULL)通常是证明一个过于自信的程序员他的代码无法防止sig11错误的简单而有趣的方法。
还必须注意,在main()之外argv将不会被定义,而__progname通常被定义为全局变量,您可以从usage()函数内部甚至在main()被调用之前使用它(例如非标准GCC构造函数)。

3
“一个严格符合POSIX标准的应用程序必须向exec函数传递至少一个参数,从而保证在这样的应用程序调用时argc的值为1或更大。”当然没有人会有意违反POSIX标准!(http://www.opengroup.org/onlinepubs/000095399/functions/exec.html) - Matthew Flaschen

4

这是一种BSD风格,绝对不可移植。


2

__progname就是argv[0],其他回复中的示例显示了使用它的弱点。虽然也不具备可移植性,但我在Linux和Android上使用/proc/self/exe上的readlink,并读取/proc/self/exefile(QNX)的内容。


由于/proc可以找到正确的可执行路径,因此必须存在某些系统函数来实现它。 - Fantastory

1
如果你的程序是通过符号链接运行的,例如,argv[0]将包含该链接的名称。
我猜__progname会包含实际程序文件的名称。
无论如何,argv[0]由C标准定义。__progname则不是。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接