参考计划时的最佳实践';s的名字用C写

参考计划时的最佳实践';s的名字用C写,c,c-preprocessor,C,C Preprocessor,当提及程序名称时,什么是最佳实践?我看到: #define PROGRAM_NAME "myprog" printf("this is %s\n", PROGRAM_NAME); 以及: printf("this is %s\n", argv[0]); 我知道,当程序不是从$PATH调用时,第二种方法将为我提供/myprog而不是myprog,并且第一种方法将保证程序名称的一致性 但是,还有什么其他因素使一种方法优于另一种方法吗?当您手头没有argv时,前者优于后者 #define PROG

当提及程序名称时,什么是最佳实践?我看到:

#define PROGRAM_NAME "myprog"
printf("this is %s\n", PROGRAM_NAME);
以及:

printf("this is %s\n", argv[0]);
我知道,当程序不是从
$PATH
调用时,第二种方法将为我提供
/myprog
而不是
myprog
,并且第一种方法将保证程序名称的一致性


但是,还有什么其他因素使一种方法优于另一种方法吗?

当您手头没有
argv
时,前者优于后者

#define PROGRAM_NAME "myprog"

void salute()
{
     // no argv available 

     printf("Hello from %s\n", PROGRAM_NAME );
}

void main( int argc, char** argv ) 
{
     salute();
}

取决于argv是否在范围内…

当您有多个链接时,第二种方法更优越。在*nix系统中,有时行为取决于调用程序的方式。因此,对程序名进行硬编码显然是一个问题——它永远无法检查这一点。

我试图在这两个方面都做到最好:

char const * program_name;

int main(int argc, char **argv) {
   program_name = argv[0];
   //...
}
如果您需要程序名在其他文件中可用,可以这样声明:

extern char const * program_name;

我声明“char const*”,因为我希望它是指向const数据的指针。我不确定这一部分是否正确。

第二种方法也可以提供字符串,如
/usr/bin/myprog
,如果这样执行的话;basename应该给出可执行文件的名称(您可以将其视为程序的名称)。。。除非它是符号链接的。。。(在这种情况下,您有链接的名称……可用于在程序行为中进行某种选择)


第一种方法将程序名“修复”为程序员想要的名称,无论用户如何重命名可执行文件或符号链接(甚至硬链接)

如果可能,我通常使用
argv[0]
basename(argv[0])
。从用户的角度来看,我认为如果他们重命名或硬链接一个可执行文件(或者其他人为他们这样做),那么他们希望它的消息以他们正在使用的名称显示,而不是以他们可能知道或不知道的其他名称显示

类似地,如果您将来发现您希望用不同的名称和不同的选项编译程序,以提供不同的版本,您是否希望将
\ifndef
包装在
\define
周围,并确保它是通过编译器命令行定义的:
-DPROGRAM\u NAME=myprog\u demo
,或者你只是想做它,它会起作用吗

例外情况可能是,如果您的使用说明是从手册页或其他文档中提取的,那么您可能确实希望将程序名硬连接到其中。但是您可能也不会使用
#define

不过,实现不需要提供
argv[0]
,因此对于最佳可移植实践,也需要处理这种情况。再说一次,如果您的系统没有提供,那么用户可能也不会在任何类型的终端上看到消息

顺便说一下:

#define PROGRAM_NAME "myprog"
puts("this is " PROGRAM_NAME);

它并没有完全回答您关于编程最佳实践的问题,但我认为您还应该记住什么对用户来说是最好的。 我个人更喜欢使用
argv[0]
引用自己的程序,即我正在调用的命令,而不是程序员在程序中硬编码的某个随机名称。一些硬编码名称令人讨厌或至少没有帮助的示例:

  • 我已经创建了一个程序的链接
  • 出于某种原因,我已经重命名了二进制文件
  • 我的
    $PATH
  • 一个程序会提示我其他调用它的方法,例如在“用法”消息中

我喜欢硬编码程序名的唯一情况是在使用GUI应用程序时。我不想把“~/foo/bar.pl”作为窗口标题。

这有什么区别吗?我不认为
argc
argv
成本太高。我现在明白你的意思了。是的,让perfect senseI明白你的意思,但在你的例子中,你基本上是在创建一个全局变量。如果你需要程序名,那么把它(argv)作为一个参数传递给sallet(),你的问题就解决了。是的,它适用于几个方法,如果在几个地方需要这个名称,并且大多数函数已经有一个大的参数列表,那么当全局常量可用时,再使用一个参数是荒谬的。无论哪种情况,我认为jonhcatfish都是一个更好的选择。@支持:如果在多个地方需要名称,那么您应该传递(或在绝对必要时使其成为全局)某种记录器对象,而不仅仅是程序名。这是什么意思“行为取决于您如何调用程序”?我真的无法理解它。@guest:例如,
gcc
g++
可能是同一个可执行文件,它检查调用它时使用的名称,并相应地修改链接器选项。不记得它是否真的是。示例:默认情况下,grep打印匹配的行。此外,还提供了三种变体程序egrep、fgrep和rgrep。egrep与grep-E相同。fgrep与grep-F相同。rgrep与grep-r.ah相同。以前从未听说过这个概念,尽管另一个例子是vi和view,它是vi的只读版本,但是它是完全相同的代码和完全相同的可执行文件。调用它查看只会以只读方式打开文件。不错。通过回答“两者”来回避哪个更好的问题,但也不错。是的,我使用过一些产品,它们看起来有几个可执行文件,但实际上只有一个有多个链接。这似乎有些疯狂,但这是一种通过多次修订保持多个工具同步的好方法。
basename
不可移植。它仅由POSIX(在libgen.h中)要求。另外,请记住,它可能会修改您提供给它的字符串,并且返回的指针可能是原始指针的偏移量,或者是静态分配的字符串(因此不要尝试释放它提供的内容)