gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 02:12:59 24 4
gpt4 key购买 nike

就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the help center为指导。




9年前关闭。




我就宏及其可读性进行了辩论。
我认为在某些情况下使用宏可以使代码更短、更易于理解并且阅读起来不那么累。

例如:

#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;
}

我更喜欢这里的第二个选项,因为它简短而紧凑,而且大写锁定文本比驼峰式大小写更清晰易读。

这种方法有什么问题吗,特别是在 C++ 中,或者它只是糟糕的(但可以接受的)风格?

最佳答案

宏是 C/C++ 的一个非常强大的特性,就像所有的 C 特性一样
默认情况下指向您的脚。考虑以下使用
你的宏:

if (doSomething())
EXIT_ON_FAILURE(s) /* <-- MISSING SEMICOLON! OH NOES!!! */
else
doSomethingElse();

是否 else属于 if在声明或 if通过扩展创建 EXIT_ON_FAILURE ?无论哪种方式,行为
缺少一个分号是完全出乎意料的。如果 EXIT_ON_FAILURE()
是一个函数,你会得到一个编译器错误。在这种情况下,你会得到
编译但做错事的代码。

这就是宏的问题。它们看起来像函数或
变量,但它们 不是 .一个写得不好的宏是礼物
继续给予。宏的每次使用都是一个潜在的微妙错误,
对宏的每次更改都有可能在代码中引入逻辑错误
你没碰过的。

一般来说,除非绝对必要,否则您应该避免使用宏。

如果需要定义常量,请使用 const变量或 enum .
一个好的编译器(你可以免费获得)会将它们变成
生成的可执行文件中的文字就像 #define'd 常量
但它也会以您期望的方式处理类型转换
显示在调试器的符号表中。

如果您需要内联函数之类的东西,请使用内联函数。
C++ 和 C99 都提供了它们和最体面的编译器(包括
免费的)已经做了很长时间的扩展。

与宏不同,函数强制它们的参数被求值,所以
inline int DOUBLE(int a) {return a+a;}

只会评估 a曾经
#define DOUBLE(a) (a + a)

将评估 a两次。这意味着
x = DOUBLE(someVeryLongFunction());

如果 DOUBLE 是一个宏,则比它是一个函数需要两倍的时间。

另外,我(故意)忘了给宏参数加上括号,所以
这个:
DOUBLE(a << b)

将给出一个完全令人惊讶的结果。你需要记住
将 DOUBLE 宏写为
#define DOUBLE(a) ((a) + (a))

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

话虽如此,是的,那里 宏将使
代码更具可读性。他们少之又少,但他们
存在。其中之一是 assert您的代码重新发明的宏。
复杂系统使用自己的自定义 assert -like 宏以配合本地调试方案,以及那些
几乎总是用宏来实现,以便获得 __FILE__ , __LINE__和条件的文本。

但即便如此,这也是典型的 assert实现:
#ifdef NDEBUG
# define assert(cond)
#else
# define assert(cond) __assert(cond, __FILE__, __LINE__, #cond)
#endif

换句话说,类函数宏扩展为函数调用。
这样,当您拨打 assert 时, 扩张还是很接近的
到它的样子和参数扩展发生的方式
你会期望的。

还有一些其他用途。基本上,任何时候你需要
将信息从构建过程本身传递给程序,它将
可能需要通过宏系统。即使那样,你
应该尽量减少接触宏的代码量以及如何
宏做了很多事情。

最后一件事。如果您想使用宏,因为您认为
代码会更快,请注意这是魔鬼在说话。在
过去,可能会发生转换小
将函数转换为宏可以显着提高性能。这些
天虽然:
  • 大多数编译器都支持内联函数。有些人甚至这样做
    自动到静态函数。
  • 现代计算机速度如此之快,您几乎肯定不会注意到
    调用即使是一个微不足道的函数的开销。

  • 仅当您的编译器不执行内联函数时 你不能只是
    用更好的替换它 您已经 经验证 那个函数调用
    开销是一个瓶颈,你能不能证明写几个宏是合理的。

    也许。

    关于c++ - 宏是否使代码更具可读性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11332947/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com