草庐IT

c++ - 自定义 C++ 断言宏

coder 2023-05-03 原文

我偶然发现了一篇内容丰富的文章:http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/ 它指出了我当前的调试宏套件中存在的大量问题。

如果您点击链接,最终版本的宏的完整代码将在文章末尾附近提供。

呈现的一般形式是这样的(如果我在转置它时错了,请有人纠正我):

#ifdef DEBUG
#define ASSERT(cond) \  
    do \  
    { \  
        if (!(cond)) \  
        { \  
            ReportFailure(#cond, __FILE__, __LINE__, 0); \
            HALT(); \
        } \  
    } while(0)  
#else  
#define ASSERT(cond) \  
    do { (void)sizeof(cond); } while(0) 

在考虑用我学到的东西修改我的代码时,我注意到那篇文章的评论中发布了一些有趣的变化:

一个是您不能将此宏与三元运算符一起使用(即 cond?ASSERT(x):func()),建议替换 if() 带有三元运算符和一些括号以及逗号运算符。后来另一位评论者提供了这个:

#ifdef DEBUG
#define ASSERT(x) ((void)(!(x) && assert_handler(#x, __FILE__, __LINE__) && (HALT(), 1)))
#else
#define ASSERT(x) ((void)sizeof(x))
#endif

我认为在这种情况下使用逻辑和 && 特别聪明,在我看来,这个版本比使用 if 甚至三元 ?:。更好的是,assert_handler 的返回值可以用来确定程序是否应该停止。虽然我不确定为什么它是 (HALT(), 1) 而不仅仅是 HALT()

我忽略的第二个版本有什么特别的缺点吗?它取消了包裹在宏周围的 do{ } while(0) 但这里似乎没有必要,因为我们不需要处理 ifs。

你怎么看?

最佳答案

在 C 和 C++ 标准库中,assert是充当函数所需的宏。该要求的一部分是用户必须能够在 表达式 中使用它。例如,使用标准 assert我可以的

int sum = (assert(a > 0), a) + (assert(b < 0), b);

功能相同

assert(a > 0 && b < 0)
int sum = a + b;

尽管前者可能不是编写表达式的好方法,但该技巧在许多更合适的情况下仍然非常有用。

这立即意味着如果一个人想要他们自己的定制ASSERT模仿标准的宏assert行为和可用性,然后使用 ifdo { } while (0)ASSERT 的定义中是没有问题的。一种仅限于这种情况下的表达式,即使用 ?:运算符或短路逻辑运算符。

当然,如果您不关心制作类似标准的自定义 ASSERT , 然后可以使用任何东西,包括 if .链接的文章似乎甚至没有考虑这个问题,这很奇怪。在我看来,类函数的断言宏肯定比非类函数的宏更有用。

至于(HALT(), 1) ... 这样做是因为 &&运算符需要一个有效的参数。 HALT()的返回值可能不代表 && 的有效参数.可能是 void据我所知,这意味着只有 HALT()根本不会编译为 && 的参数. (HALT(), 1)总是计算为 1并具有类型 int ,它始终是 && 的有效参数.所以,(HALT(), 1)始终是 && 的有效参数无论 HALT() 的类型如何.

您对 do{ } while(0) 的最后评论似乎没有多大意义。将宏包含在 do{ } while(0) 中的要点是处理外部if s,而不是 if s 在宏定义中。您总是必须处理外部 if s,因为您的宏总是有可能在外部 if 中使用.在后一个定义中 do{ } while(0)不需要,因为该宏是一个表达式。而且作为一个表达式,它与外部的if自然已经没有问题了。 s。所以,没有必要对它们做任何事情。此外,正如我上面所说,将其包含在 do{ } while(0) 中会完全违背它的目的,把它变成一个不表达的东西。

关于c++ - 自定义 C++ 断言宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5252375/

有关c++ - 自定义 C++ 断言宏的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

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

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

  4. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  5. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  6. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  7. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  8. ruby - 如何在 Grape 中定义哈希数组? - 2

    我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>

  9. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  10. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

随机推荐