在我工作的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不是。