jjzjj

c++ - 用于调试日志语句的预处理器宏是否在 C++ 中占有一席之地?

coder 2024-02-02 原文

最近我一直在阅读 Scott Meyers 的 Effective C++ Second Edition,以改进 C++ 最佳实践。他列出的项目之一鼓励 C++ 程序员避免预处理器宏并“更喜欢编译器”。他甚至说除了#include 和#ifdef/#ifndef 之外,C++ 中几乎没有使用宏的理由。

我同意他的推理,因为你可以完成下面的宏

#define min(a,b) ((a) < (b) ? (a) : (b))

具有以下C++语言特性

template<class T>
inline const T & min(const T & a, const T & b) {
    return a < b ? a : b;
}

其中 inline 为编译器提供了删除函数调用和插入内联代码和模板的选项,这些代码和模板可以处理具有重载或内置 > 运算符的多种数据类型。

EDIT-- 如果 a 和 b 的数据类型不同,此模板声明将不会完全匹配指定的宏。有关示例,请参阅 Pete 的评论。

但是,我很想知道使用宏进行调试日志记录在 C++ 中是否有效。如果我在下面介绍的方法不是很好的做法,有人会建议另一种方法吗?

去年我一直在使用 Objective-C 编写代码,我最喜欢的 2D 引擎之一 (cocos2d) 使用宏来创建日志记录语句。宏如下:

/*


* if COCOS2D_DEBUG is not defined, or if it is 0 then
 *  all CCLOGXXX macros will be disabled
 *
 * if COCOS2D_DEBUG==1 then:
 *      CCLOG() will be enabled
 *      CCLOGERROR() will be enabled
 *      CCLOGINFO() will be disabled
 *
 * if COCOS2D_DEBUG==2 or higher then:
 *      CCLOG() will be enabled
 *      CCLOGERROR() will be enabled
 *      CCLOGINFO() will be enabled
 */


#define __CCLOGWITHFUNCTION(s, ...) \
NSLog(@"%s : %@",__FUNCTION__,[NSString stringWithFormat:(s), ##__VA_ARGS__])

#define __CCLOG(s, ...) \
NSLog(@"%@",[NSString stringWithFormat:(s), ##__VA_ARGS__])


#if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0
#define CCLOG(...) do {} while (0)
#define CCLOGWARN(...) do {} while (0)
#define CCLOGINFO(...) do {} while (0)

#elif COCOS2D_DEBUG == 1
#define CCLOG(...) __CCLOG(__VA_ARGS__)
#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__)
#define CCLOGINFO(...) do {} while (0)

#elif COCOS2D_DEBUG > 1
#define CCLOG(...) __CCLOG(__VA_ARGS__)
#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__)
#define CCLOGINFO(...) __CCLOG(__VA_ARGS__)
#endif // COCOS2D_DEBUG

这个宏提供了令人难以置信的实用程序,我想将其合并到我的 C++ 程序中。编写有用的日志语句就像

CCLOG(@"Error in x due to y");

更好的是,如果 COCOS2D_DEBUG 设置为 0,那么这些语句将永远见不到天日。检查条件语句以查看是否应使用日志记录语句没有开销。这在从开发过渡到生产时很方便。如何在 C++ 中重现同样的效果?

那么这种类型的宏属于 C++ 程序吗?是否有更好、更 C++ 的方法来执行此操作?

最佳答案

首先,Scott 的声明是在宏还没有出现的时候发表的 由于历史原因,使用过度。虽然它是 通常是正确的,但在某些情况下宏是有意义的。 其中 日志记录,因为只有宏可以自动 插入 __FILE____LINE__ .另外,只有一个宏可以 决心一无所有(尽管根据我的经验, 这没什么大不了的)。

您展示的宏在 C++ 中并不常见。有 两种常用的日志记录变体:

#define LOG( message ) ... << message ...

允许以 " x = " << x 形式发送消息,并且可以是 通过重新定义宏完全抑制,并且

#define LOG() logFile( __FILE__, __LINE__ )

哪里logFile返回 std::ostream 的包装器, 哪个 定义 operator<< ,并允许这样的事情:

LOG() << "x = " << x;

这样做,LOG() 右边的所有表达式 将始终被评估,但正确完成,不会格式化 除非日志处于事件状态,否则将完成。

关于c++ - 用于调试日志语句的预处理器宏是否在 C++ 中占有一席之地?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18047656/

有关c++ - 用于调试日志语句的预处理器宏是否在 C++ 中占有一席之地?的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  5. ruby - inverse_of 是否适用于 has_many? - 2

    当我使用has_one时,它​​工作得很好,但在has_many上却不行。在这里您可以看到object_id不同,因为它运行了另一个SQL来再次获取它。ruby-1.9.2-p290:001>e=Employee.create(name:'rafael',active:false)ruby-1.9.2-p290:002>b=Badge.create(number:1,employee:e)ruby-1.9.2-p290:003>a=Address.create(street:"123MarketSt",city:"SanDiego",employee:e)ruby-1.9.2-p290

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  8. ruby - "undefined method"用于 rails 模型 - 2

    我正在使用带有Rails的Devise,我想添加一个方法“getAllComments”,所以我这样写:classUser在我的Controller中:defdashboard@user=current_user@comments=@user.getAllComments();end当我访问我的url时,我得到了undefinedmethod`getAllComments'for#我做错了什么?谢谢 最佳答案 因为getAllComments是一个类方法,而您正试图将其作为实例方法访问。您要么需要访问它:User.getAllCom

  9. Ruby-vips 图像处理库。有什么好的使用示例吗? - 2

    我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby​​代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby​​-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby​​-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby​​-vips的github页面上的链接,我们将不胜感激!如果有ruby​​-

  10. Ruby on Rails regexp equals-tilde 与 array include 用于检查选项列表 - 2

    我正在使用Rails3.2.3和Ruby1.9.3p0。我发现我经常需要确定某个字符串是否出现在选项列表中。看来我可以使用Ruby数组.includemethod:或正则表达式equals-tildematchshorthand用竖线分隔选项:就性能而言,一个比另一个好吗?还有更好的方法吗? 最佳答案 总结:Array#include?包含String元素,在接受和拒绝输入时均胜出,对于您的示例只有三个可接受的值。对于要检查的更大的集合,看起来Set#include?和String元素可能会获胜。如何测试我们应该根据经验对此进行测试

随机推荐