1

我正在研究 coreutils 源代码以更好地编程,我在 base64.c 和其他代码中发现了这些行:

while ((opt = getopt_long (argc, argv, "diw:", long_options, NULL)) != -1)
switch (opt)
{
// ... other stuff
  case_GETOPT_HELP_CHAR; // <- this especially

  case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
// .. other stuff again

我不知道这到底是什么意思,直到我在 system.h 中找到了这个:

#define case_GETOPT_HELP_CHAR           \
 case GETOPT_HELP_CHAR:         \
 usage (EXIT_SUCCESS);          \
 break;

我不知道您实际上可以制作包含这么多语句的宏!在宏中使用这么多语句是不是很冒险,或者这是我应该学习的一种很好的编码风格?

编辑:我还注意到 coreutils 中实际上使用了很多 MACROS。这让我有点困惑,因为我来自 C++ 背景。

#define STREQ(a, b) (strcmp (a, b) == 0)

比如上面这个,真的有必要吗?它使阅读代码变得更加困难,并且仅在 inf 语句中执行 STREQ 并没有节省多少

EDIT2:另一方面,我非常喜欢这个,感谢杰伊:

 #define COMMAND(NAME)  { #NAME, NAME ## _command }

 struct command commands[] =
 {
   COMMAND (quit),
   COMMAND (help),
   ...
 };
4

4 回答 4

1

只要编写正确,使用这样的宏就没有风险(如果不是,可能会导致编译错误或意外行为)。但是,除非您需要它们,否则请避免使用它们——它们往往会使代码难以阅读。

例如,宏#define foo() bar(); bar会很危险,因为if(...) foo();最终bar()总是会被调用(在这种情况下,您会将宏代码包装在 a 中do{ ... }while(0)

于 2012-05-15T18:04:08.417 回答
1

这取决于。如果宏大大减少了代码大小,或者使在一个地方修改东西变得相当容易,那么无论如何,去吧,即使它有时在代码诗人的眼中看起来很丑。

在特定情况下,我持怀疑态度。首先,宏以分号结尾,宏的用法也是如此,因此扩展以分号结尾,其中一个是空语句。一些 lints 对这些发出警告。在多语句宏之后强制使用分号的规范方法是

#define FOO(x) do { statement(x); stmnt; } while (0)

但在这种情况下,由于case. (意外的双关语,呵呵)。

其次,我不确定这个宏是否真的在某处被重用。如果不是,那么我认为它比优雅的hackery 更多的是代码混淆。另一方面,它看起来system.h也包含在其他实用程序中,并且在许多 coreutils 实用程序之间保持一致性是有一点意义的,例如,始终使用相同的选项 char 表示“帮助”、“详细”等。

于 2012-05-15T18:14:42.327 回答
0

这没有风险,也没有任何问题。

请阅读此处并使用 Google 了解有关宏的更多信息。一旦您对宏有了一些了解,您将能够决定何时使用什么。

还要检查这个 stackoverflow链接。:) 。

于 2012-05-15T18:02:10.250 回答
0

快速阅读答案会告诉您,这是一个偏好问题。有些人喜欢,有些人不喜欢。
我不。

我的主要问题是使用它的代码并不是真正的 C 代码。所以当你读了它,你知道了C,你仍然无法理解它。

如果使用不当,此类定义可能会导致奇怪且难以调试的问题。您查看代码,它看起来正确,但事实并非如此。该case_GETOPT_HELP_CHAR宏似乎不太容易出现此类错误。case_GETOPT_VERSION_CHAR,有参数,可能更危险。

STREQ是一个更好的宏。它使事情比strcmp(a,b)==0(我总是觉得这个令人困惑)更清楚一些。
根据经验,我更喜欢可能是函数的宏。如果你愿意,你可以实现STREQ为一个函数,但不是case_GETOPT_HELP_CHAR.

COMMAND是一个不同的故事。它有一些丑陋的地方,但有一个强有力的理由——它消除了重复。如果没有宏技巧,您将不得不重复两次命令名称。
另一方面,考虑看到这个quit_command函数并试图找到调用它的地方的可怜人。他可以在各个来源中搜索这个名字,但他不会找到它。

于 2012-05-15T18:46:48.503 回答