使用'__progname'而不是argv

在我工作的C / Unix环境中,我看到一些开发人员使用__progname而不是argv [0]来使用()消息。 这有什么好处吗? __progname和argv [0]有什么区别? 它是否便携?

__progname不是标准的,因此不能移植,比较喜欢argv[0] 。 我想__progname可以查找一个字符串资源来获得不依赖于你运行它的文件名的名称。 但是argv[0]会给你他们实际运行的名字,我会发现它更有用。

使用__progname可以在保持程序名称的同时更改argv[]数组的内容。 一些常用工具,如getopt()在处理参数时修改argv[]

为了便于携带,您可以在程序启动时将strcopy argv[0] progname到您自己的程序progname缓冲区中。

这里还有一个GNU扩展,所以人们可以从main()外部访问程序调用名称,而不用手动保存。 然而,手动操作可能会更好。 从而使其可移植,而不依赖于GNU扩展。 不过,我在这里提供了可用文档的摘录。

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

“如果有任何系统调用失败,许多不读取终端输入的程序将被设计为退出。按照惯例,来自这样一个程序的错误信息应该以程序的名字开头,sans目录,你可以在变量中找到这个名字program_invocation_short_name ;完整的文件名存储变量program_invocation_name

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

  • 变量:char * program_invocation_short_name该变量的值是用来调用当前进程中运行的程序的名称,并删除目录名称。 (也就是说,它和program_invocation_name相同,直到最后一个斜杠,如果有的话)。

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

可移植性注意:这两个变量是GNU扩展。 如果您希望程序使用非GNU库,则必须将argv[0]的值保存在main中,然后自行剥离目录名称。 我们添加了这些扩展,以便能够编写不需要来自main的明确合作的独立的错误报告子例程。“

这是一个BSDism,绝对不是便携式的。

我发现argv [0]至少有两个潜在的问题。

首先,如果execve()调用者是邪恶或粗心,argv [0]或argv本身可能是NULL。 调用execve(“foobar”,NULL,NULL)通常是一个简单而有趣的方式来证明一个过于自信的程序员,他的代码不是sig11-proof。

还必须注意的是,argv不会在main()之外定义,而__progname通常被定义为一个全局变量,你可以在你的usage()函数内部甚至在调用main()之前使用这个全局变量(就像非标准的GCC构造函数一样) 。

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

如果您的程序是使用例如符号链接运行的,则argv [0]将包含该链接的名称。

我猜__progname将包含实际的程序文件的名称。

无论如何,argv [0]是由C标准定义的。 __progname不是。