【问题标题】:use of assert and static assert functions使用断言和静态断言函数
【发布时间】:2014-01-17 10:37:18
【问题描述】:

我正在尝试了解 static_assert 和 assert 的使用以及它们之间的区别,但是关于此的来源/解释很少

这里有一些代码

// ConsoleApplication3.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "conio.h"
#include "cassert"
#include "iostream"


int main()
{
    assert(2+2==4);
    std::cout << "Execution continues past the first assert\n";
    assert(2+2==5);
    std::cout << "Execution continues past the second assert\n";
    _getch();
}

cmets 将不胜感激(因为我正在学习“如何使用 c++”)

在 cmd 中输出

Execution continues past the first assert
Assertion failed: 2+2==5, file c:\users\charles\documents\visual studio 2012\pro
jects\consoleapplication3\consoleapplication3\consoleapplication3.cpp, line 14

我一直在尝试找出它的不同方法和用途,但据我了解,它是运行时检查和 if 语句的另一种“类型”

有人可以澄清一下用途并解释每个人的作用和区别吗?

【问题讨论】:

    标签: c++ assert assertions static-assert


    【解决方案1】:

    您可以将断言视为健全性检查。你知道某些条件应该为真,除非你搞砸了,所以断言应该通过。如果您确实搞砸了某些事情,则断言将失败,并且您会被告知有问题。它只是为了确保您的代码的有效性。

    当条件为常量表达式时,可以使用static_assert。这基本上意味着编译器能够在程序实际运行之前评估断言。您将收到警告,static_assert 在编译时失败,而普通的assert 只会在运行时失败。在您的示例中,您可以使用 static_assert,因为表达式 2+2==42+2==5 都是常量表达式。

    static_asserts 对于检查诸如模板参数之类的编译时构造很有用。例如,您可以断言给定的模板参数 T 必须是具有以下内容的 POD 类型:

    static_assert(std::is_pod<T>::value, "T must be a POD type");
    

    请注意,您通常只希望在调试期间检查运行时断言,因此您可以通过 #defineing NDEBUG 禁用 assert

    【讨论】:

    • 感谢您的深入解释,我只是好奇,是否需要任何“#includes”才能使 assert/static_assert 工作?
    • 对于断言,您需要#include &lt;cassert&gt;(在 C++ 中),对于 static_assert,没有包含。如果可用,它是一个内置的编译器。不过,您需要为 C++11/C11 编译! (-std=c++11/-std=c11 gcc 的参数)。
    • @user2699451 对于static_assert,您无需执行任何操作。这是一个语言特性。对于assert,您应该包括&lt;cassert&gt;
    • @JonasWielicki 这适用于 C++11,但不适用于 C11。 C11 有_Static_assert 作为一个新关键字,以及一个标准头(不确定是哪个,可能是&lt;assert.h&gt;)将static_assert 定义为扩展为_Static_assert 的宏。它类似于C99中的bool/_Bool,其中bool&lt;stdbool.h&gt;中定义。
    • 哦有趣的@hvd,不知道!
    【解决方案2】:

    assert() 是一个宏,其扩展取决于是否定义了宏NDEBUG。如果是这样,assert() 不会扩展到任何东西 - 这是一个无操作。当NDEBUG 未定义时,assert(x) 扩展为运行时检查,如下所示:

    if (!x) cause_runtime_to_abort()
    

    在“发布”版本中定义NDEBUG 并在“调试”版本中未定义是很常见的。这样,assert()s 只会在调试代码中执行,根本不会将其变为发布代码。您通常使用assert() 来检查应该始终为真的事物——例如,函数的前置条件和后置条件或类的不变量。失败的assert(x) 应该意味着“程序员认为x 成立,但代码中某处(或他们的推理)中的错误使这不正确。”


    static_assert()(在 C++11 中引入)是一个关键字 - 类似于例如typedef。它只能用于 compile-time 表达式,如果失败,则会导致编译错误。它不会产生任何目标代码,根本不会执行。

    static_assert() 主要用于模板,如果您想防止错误地实例化模板。例如:

    template <class IntType>
    IntType foo(IntType x)
    {
      static_assert(std::is_integral<IntType>::value, "foo() may be used with integral types only.");
      // rest of the code
    }
    

    这样,尝试使用例如调用foo() float 将导致编译时错误并显示合理的消息。

    有时,static_assert() 在模板之外也很有用,例如像这样:

    static_assert(sizeof(void*) > 4, "This code does not work in 32 bits");
    

    【讨论】:

      【解决方案3】:

      static_assert 在编译时评估,assert 在运行时评估。

      【讨论】:

        【解决方案4】:

        我怀疑你找不到任何来源,但我还是会给出一些解释。

        assert 用于运行时检查,它永远不会失败。如果它们失败,程序将不正常地终止。您可以通过指定编译时间标志来禁用发布版本的断言。因为断言不应该失败(毕竟它们是断言),在一个工作程序中,这不应该有任何区别。但是,断言中的表达式不得有副作用,因为不能保证它们会被执行。示例:

        unsigned int add_non_negative_numbers(int a, int b)
        {
            // good
            assert(a > 0);
            assert(b > 0);
            return (unsigned int)a + (unsigned int)b;
        }
        
        void checked_read(int fd, char *buffer, int count)
        {
            // BAD: if assertions are disabled, read() will _not_ be called
            assert(read(fd, buffer, count) == count);
            /* better: not perfect though, because read can always fail
            int read_bytes = read(fd, buffer, count);
            assert(read_bytes == count);
            */
        } 
        

        static_assert 是新的,可用于执行编译时检查。它们在失败时会产生编译器错误并阻止程序编译:

        static_assert(sizeof(char) == 1, "Compiler violates the standard");
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-13
          相关资源
          最近更新 更多