像“case_GETOPT_HELP_CHAR”这样的宏有风险吗?

时间:2012-05-15 17:57:34

标签: c coding-style

我正在研究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;

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

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

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

例如上面这个,是否真的有必要?它使得阅读代码更加困难,只需在inf语句中执行STREQ就可以节省很多时间

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

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

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

4 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

这取决于。如果宏大大减少了代码大小,或者只是在一个地方修改内容变得相当容易,那就去吧,即使它有时看起来对代码诗人的眼睛看起来很难看。

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

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

但是在这种情况下由于case而失败了。 (意外的双关语,呵呵)。

其次,我不确定这个宏是否实际上在某个地方被重用了。如果没有,那么我认为它比典型的hackery更多代码混淆。另一方面,看起来system.h也包含在其他实用程序中,并且在多个coreutils实用程序之间保持一致性是有意义的,例如总是使用相同的选项char“help”,“verbose”等。

答案 2 :(得分:0)

这没有风险,并且没有任何错误。

请阅读here并使用Google了解有关宏的更多信息。一旦你对宏有了很好的理解,你就可以决定何时使用它。

同时检查此stackoverflow link。 :)

答案 3 :(得分:0)

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

我的主要问题是使用它的代码不是真正的C代码。因此,当你阅读它并且你知道C时,你仍然无法理解它。

如果使用不当,这些定义可能导致奇怪且难以调试的问题。你看一下代码,看起来是对的,但事实并非如此。 case_GETOPT_HELP_CHAR宏似乎不太容易出现此类错误。具有参数的case_GETOPT_VERSION_CHAR可能更危险。

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

COMMAND是另一回事。有一些丑陋的东西,但强有力的理由 - 它消除了重复。如果没有宏观技巧,你必须重复两次命令名称 另一方面,考虑看到quit_command函数的穷人,并试图找到它的调用位置。他可以在各个来源中搜索这个名字,他也找不到它。