C++ 宏是否使代码更具可读性?

C++ 宏是否使代码更具可读性?,c++,c,code-readability,C++,C,Code Readability,我就宏和它们的可读性进行了辩论。 我认为,在某些情况下,使用宏可以使代码更短、更容易理解、阅读更轻松 例如: #include <iostream> #define EXIT_ON_FAILURE(s) if(s != 0) {std::cout << "Exited on line " << __LINE__ << std::endl; exit(1);} inline void exitOnFailure(int s, int lineNu

我就宏和它们的可读性进行了辩论。 我认为,在某些情况下,使用宏可以使代码更短、更容易理解、阅读更轻松

例如:

#include <iostream>

#define EXIT_ON_FAILURE(s) if(s != 0) {std::cout << "Exited on line " << __LINE__ << std::endl; exit(1);}

inline void exitOnFailure(int s, int lineNum) {
    if (s != 0) {
        std::cout << "Exited on line " << lineNum << std::endl; 
        exit(1);
    }
}

int foo() {
    return 1;
}

int bar(int a, int b, int c) {
    return 0;
}

int main() {
    // first option
    if (foo() != 0) {
        std::cout << "Exited on line " << __LINE__ << std::endl;
        exit(1);    
    }
    if (bar(1, 2, 3) != 0) {
        std::cout << "Exited on line " << __LINE__ << std::endl;
        exit(1);    
    }

    // second option
    EXIT_ON_FAILURE(foo());
    EXIT_ON_FAILURE(bar(1, 2, 3));

    // third option
    exitOnFailure(foo(), __LINE__);
    exitOnFailure(bar(1, 2, 3), __LINE__);

    return 0;
}
#包括

如果定义(Ex.In)失败(s),如果(s!=0){STD::CUT

RealMe宏可以简化函数,使其更易于阅读。但是应该考虑使用内联函数代替.< /P>

在您的示例中,ExtIXON-OUTION,可以是内联函数。宏不仅使编译器ErOS不准确(它可能会导致一些ErrOS显示在错误的地方),但是在使用宏时有一些事情要小心,特别是变量,考虑这个例子:

#define MY_MACRO(s) if (s * 2 >= 20) foo()

// later on your code:
MY_MACRO(5 + 5);
虽然我可以调用foo(),但它不会,因为如果(10*2>=20)foo()
,它不会扩展到
,如果(5+5*2>=20)foo()
,它会扩展到
。所以在定义宏时,需要记住始终在变量周围使用()


宏也使程序更难调试。

有时宏确实是您所需要的,但您应该尽量减少宏的数量。在您的示例中,已经有一个名为“assert”的宏,您可以使用它来代替创建新的宏


C++有很多特性,允许你在宏中不需要宏,C++中的宏应该比C++代码中的宏要少。 默认情况下指向你的脚。考虑下面的用法 您的宏:

if (doSomething())
    EXIT_ON_FAILURE(s)   /* <-- MISSING SEMICOLON! OH NOES!!! */
else
    doSomethingElse();
将只对
a
进行一次评估

#define DOUBLE(a) (a + a)
将计算
a
两次。这意味着

x = DOUBLE(someVeryLongFunction());
如果DOUBLE是宏,则所用时间将是函数的两倍

另外,我(故意)忘记了在宏参数中插入括号,所以 这:

换句话说,您需要完美地编写一个宏,以便最小化 射中自己脚的机会如果你犯了错误, 你将为此付出多年的代价

尽管如此,是的,在某些情况下,宏会 代码更具可读性。它们非常少,但它们 存在。其中之一是
assert
宏,您的代码重新创建了该宏。 对于复杂的系统来说,使用自己的定制是很常见的
assert
-与本地调试方案关联的类宏,以及 几乎总是使用宏来实现,以便获取
\uuuu文件\uuu
\uuuuuu行\uuuuuu
和条件的文本

但即便如此,典型的
assert
也是这样实现的:

#ifdef NDEBUG
#   define assert(cond)
#else
#   define assert(cond) __assert(cond, __FILE__, __LINE__, #cond)
#endif
换句话说,类似于宏的函数扩展为函数调用。 这样,当您调用
assert
时,扩展仍然非常接近 它看起来像什么,参数展开的方式是 你会预料到的

还有一些其他用途。基本上,只要你需要,随时都可以 将信息从构建过程本身传递到程序,它将 可能需要通过宏系统。尽管如此,您 应尽量减少接触宏的代码量以及如何 宏有很多作用

最后一件事,如果你想使用宏,因为你认为 代码会更快,请注意这是魔鬼在说话 在过去,可能有一些情况下,转换小 宏中的函数显著提高了性能 尽管如此:

  • 大多数编译器支持内联函数,有些甚至支持内联函数 自动转换为静态函数

  • 现代计算机速度如此之快,你几乎肯定不会注意到 调用一个微不足道的函数的开销

  • 只有当您的编译器不执行内联函数时,您才能 将其替换为一个更好的您已经验证了该函数调用 开销是一个瓶颈,您可能需要编写一些宏


    如果你在C++中通过了代码,你可以对函数进行同样的处理。我可以说C++中的宏没有错误,另一方面,它们就像斑块:最好避免!单独的事实是,他们不遵循范围,应该是一个指示邪恶宏的可能的方式。我通常都是这样做的:一个函数,比如“代码> ExtEng失败”。ure
    和宏退出\u ON_FAILURE`只传递参数加上
    \uuuu文件\uuuuu
    \uuuu行\uuuuuuu
    \uuuuu函数\uuuuu
    @MFH它们是一块斑块?使用?我想你的意思是瘟疫。看起来你在重新发明assert()宏。有时您不想使用assert,因为它可能会吓唬您的用户。在这种情况下,信息输出可能会更好。@WhiteZebra他们应该害怕什么?assert背后的想法是在调试版本中使用它,以便在软件发布之前发现可预防的问题。正因为如此,assert宏被定义为no发布模式下的操作(请参阅)…+1“如果您想使用宏,因为您认为代码会更快,请注意这是魔鬼说话。”当您过早优化时,回答得很好!尤其是良好宏使用的示例(调试断言)。
    DOUBLE(a << b)
    
    #define DOUBLE(a) ((a) + (a))
    
    #ifdef NDEBUG
    #   define assert(cond)
    #else
    #   define assert(cond) __assert(cond, __FILE__, __LINE__, #cond)
    #endif