【问题标题】:assert() with message带有消息的断言()
【发布时间】:2011-05-03 09:54:06
【问题描述】:

我在某处看到断言以以下方式与消息一起使用:

assert(("message", condition));

这似乎工作得很好,除了 gcc 抛出以下警告:

warning: left-hand operand of comma expression has no effect

如何停止警告?

【问题讨论】:

  • 查看this相关问题。

标签: c gcc compiler-warnings assert


【解决方案1】:

使用-Wno-unused-value 停止警告; (选项-Wall 包括-Wunused-value)。

我认为更好的是使用另一种方法,例如

assert(condition && "message");

【讨论】:

  • 不错,我通常会断言(condition /* message */)。
  • 这有时会在 Visual Studio 中给出“条件表达式是常量”警告。关于如何在不抑制警告的情况下删除警告的任何想法?
  • @Samaursa:您可能对普通的condition 有疑问。编译器是否也仅使用assert(condition); 发出警告?
  • 它没有。有趣的是,OP的原始问题代码是VS警告的解决方案! assert((Msg, Cond)); 在 VS 2008 上无警告工作。
  • assert((<cond>) && "msg"); 导致 CppCheck (v1.90) 生成“incorrectStringBooleanError”警告。
【解决方案2】:

试试:

#define assert__(x) for ( ; !(x) ; assert(x) )

这样使用:

assert__(x) {
    printf("assertion will fail\n"); 
}

只有在断言失败时才会执行该块。

重要提示:此方法将对表达式x 求值两次,以防x 求值为false! (第一次,for 循环检查其条件;第二次,assert 评估传递的表达式!)

【讨论】:

  • 这样做的好处是,如果您愿意,可以使用 assert__(foo); 省略该消息,分号将结束该块。
  • 如果(x) 只返回一次true,这样的实现将不起作用:string("a") a; assert__(a.append("b") == "ab") { ... }
  • 为什么是for 而不是if?
  • 这似乎在 GCC 中不起作用。失败的assert 会停止程序执行并且不会调用printf。
  • @vil assert 不可能在 printf 之前停止程序,因为直到 printf 之后才会调用 assert。
【解决方案3】:

如果你想传递一个格式化的消息,你可以使用以下宏:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <assert.h>

#define clean_errno() (errno == 0 ? "None" : strerror(errno))
#define log_error(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
#define assertf(A, M, ...) if(!(A)) {log_error(M, ##__VA_ARGS__); assert(A); }

然后像 printf 一样使用它:

// With no args
assertf(self != NULL,"[Server] Failed to create server.");

// With formatting args
assertf((self->socket = u_open(self->port)) != -1,"[Server] Failed to bind to port %i:",self->port);
// etc...

输出:

[错误] (../src/webserver.c:180: errno: 地址已在使用中) [服务器] 绑定 8080 端口失败:webserver: ../src/webserver.c:180: server_run: 断言`(self->socket = u_open(self->port)) != -1' 失败。

基于http://c.learncodethehardway.org/book/ex20.html

【讨论】:

  • 不幸的是,这不是便携式的。 C99 要求您在可变参数宏中至少使用一个可选参数(例如:assertf(x == y, "x does not equal y") 违反了标准。不过,这很容易通过assertf(x == y, "%s", "x does not equal y") 纠正)。它还依赖于 gcc 扩展 ##__VA_ARGS__,这不一定是件坏事,但它确实降低了便携性
【解决方案4】:

按照传统,(void) 会告知编译器您有意忽略了一个表达式:

/* picard.c, TNG S6E11. */
#define assertmsg(x, msg) assert(((void) msg, x))
assertmsg(2+2==5, "There! are! four! lights!");

【讨论】:

    【解决方案5】:

    采用const char* 并返回true 的函数可能会让您免于各种警告:

    #include <assert.h>
    
    int always_true(const char *msg) {
        return 1;
    }
    
    #define assert_msg(expr, msg) assert((expr) && always_true(msg))
    

    【讨论】:

      【解决方案6】:

      对于开关的意外默认情况,一个选项是

      assert(!"message");
      

      【讨论】:

      • 这似乎总是错误的。正在测试的条件在哪里?
      • 这对于开关的意外默认情况很有用。
      • 这虽然是真的,但与原始问题没有任何关系。
      【解决方案7】:

      就我而言,我更改了@pmg 的答案以便能够控制输出。 (... &amp;&amp; "message") 对我不起作用。

      #include <assert.h>
      #include <stdio.h>
      
      #define __DEBUG__ 1
      
      assert ((1 == 1) && 
             (__DEBUG__ && printf("  - debug: check, ok.\n")) || !__DEBUG__);
      

      【讨论】:

        【解决方案8】:

        您可以编写自己的宏来提供与_Static_assert(expr, msg) 相同的用法:

        #include <assert.h>
        #include <stdbool.h>
        #include <stdio.h>
        
        
        /*
         * void assert_msg(bool expr, const char *msg);
         */
        #if !defined(NDEBUG)
        #define assert_msg(expr, msg)   do                  \
        {                                                   \
                const bool  e_ = expr;                      \
                                                            \
                if (!e_) {                                  \
                        fputs(msg, stderr);                 \
                        fputc('\n', stderr);                \
                        assert(e_);                         \
                }                                           \
        } while (0)
        #else
        #define assert_msg(expr, msg)   do                  \
        {                                                   \
                                                            \
                if (!(expr))                                \
                        warn_bug(msg);                      \
        } while (0)
        #endif
        

        我还有一个宏warn_bug() 打印程序的名称、文件、行、函数、errno 值和字符串以及用户消息,即使断言被禁用。它背后的原因是它不会破坏程序,但它会警告可能存在错误。不过,如果defined(NDEBUG),您可以将assert_msg 定义为空。

        【讨论】:

          【解决方案9】:

          根据以下链接 http://www.cplusplus.com/reference/clibrary/cassert/assert/

          assert 只需要表达式。可能是你使用了一些重载函数。

          据此,只允许表达,因此您会收到此警告。

          【讨论】:

          • 内括号可以:assert( ("message", condition) );这是C:没有重载。
          • 看不出 C++ 网站与 C 问题有什么相关性。
          猜你喜欢
          • 1970-01-01
          • 2017-02-05
          • 1970-01-01
          • 1970-01-01
          • 2012-08-08
          • 1970-01-01
          • 1970-01-01
          • 2021-09-12
          • 2018-03-07
          相关资源
          最近更新 更多