【问题标题】:Multiple errors from C assert macro来自 C 断言宏的多个错误
【发布时间】:2017-08-14 15:43:34
【问题描述】:

我有一个断言宏定义为:

#define likely(cond) (__builtin_expect((cond), 1))
#define unlikely(cond) (__builtin_expect(!!(cond), 0))

static void assert_fail(const char *__assertion, const char *__file,
                           unsigned int __line, const char *__function) {
    fprintf(stderr, "\nASSERT failed %s:%d %s()\n%s\n", __file, __line, __function, __assertion);

    void *array[50];
    size_t size = backtrace(array, 50);     // Fill out array of pointers to stack entries
    backtrace_symbols_fd(&array[1], size, STDERR_FILENO);
    exit(1);
}

#define assert(expr) ( likely(expr) ? (void) (0) : \
                       assert_fail(#expr, __FILE__, __LINE__, __func__ ))

这很好用,除非你在断言条件中犯了一个简单的错误,例如错误的变量名:

assert(size > 0);

它会打印一个完全合理的错误,然后是 5 个注释(包括重复),这使得它更难阅读。有没有什么理智的方法可以解决这个问题,使它更容易阅读?核心问题似乎是宏的使用,但鉴于__FILE____LINE__等的使用,我看不出如何避免这种情况。

如果可能的话,禁用“注意:每个未声明的标识符只为每个函数报告一次”会减少一半(尽管我找不到任何方法)

abc.c: In function 'init':
abc.c:53:12: error: 'size' undeclared (first use in this function)
     assert(size > 0);
            ^
include/assert.h:21:41: note: in definition of macro 'likely'
 #define likely(cond) (__builtin_expect((cond), 1))
                                         ^
abc.c:53:5: note: in expansion of macro 'assert'
     assert(size > 0);
     ^
abc.c:53:12: note: each undeclared identifier is reported only once for each function it appears in
     assert(size > 0);
            ^
include/assert.h:21:41: note: in definition of macro 'likely'
 #define likely(cond) (__builtin_expect((cond), 1))
                                         ^
abc.c:53:5: note: in expansion of macro 'assert'
     assert(size > 0);
     ^

【问题讨论】:

  • 第一条错误消息足以诊断此问题。像往常一样修复它
  • 我从 gcc 切换到 clang 并且大部分都修复了它。在这种情况下,错误消息似乎得到了更好的考虑,据称还有许多其他错误消息。

标签: c error-handling assert


【解决方案1】:

作为一般规则,在处理编译器错误时,先解决发现的第一个错误,然后重新编译。这样您就不会浪费时间追查级联错误。

在这种特殊情况下,您会注意到您有一个“错误”行,后面跟着几个“注释”行。每当您看到“注释”消息时,它都会为您提供有关最新“错误”或“警告消息”的附加信息。你不应该隐藏这样的消息(我不相信你可以),因为它们可以为你提供关于错误真正来源的有价值的信息。

以下是这些“注释”消息有用的示例:

#include <stdio.h>

void f1(double x);

int main()
{
    f1(3);
    return 0;
}


void f1(int x)
{
    printf("x=%d\n", x);
}

在此代码中,f1 的声明与定义不匹配。编译器生成以下消息:

x1.c:12:6: error: conflicting types for ‘f1’
 void f1(int x)
      ^
x1.c:3:6: note: previous declaration of ‘f1’ was here
 void f1(double x);

“错误”消息告诉您第 12 行的定义与声明不匹配,但没有说明它与哪个声明冲突。这出现在随后的“注释”消息中。在大型项目中,如果没有“注释”消息,您可能很难找到冲突。

【讨论】:

  • 明白了,这里特别麻烦,因为有多个层。能够只为这个宏取消注释会很有用。特别是当它重复多个注释告诉我每个未声明的标识符只报告一次时。扩展可能的宏内联将其从 6 降至 4。
【解决方案2】:

如果表达式的计算结果为 TRUE,则 assert() 什么也不做。如果表达式的计算结果为 FALSE,assert() 在 stderr 上显示错误消息(用于显示错误消息和诊断的标准错误流)并中止程序执行。

【讨论】:

  • 欢迎来到 Stack Overflow。请尽快阅读AboutHow to Answer 页面。尽管您提供的信息是准确的,但它并不能回答所提出的问题。因此,它没有帮助。我建议删除它。
  • 曾几何时,我们都是。对于我们中的一些人来说,“从前”是很久以前的事了,那时还没有互联网或万维网。
猜你喜欢
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-14
  • 2015-06-10
相关资源
最近更新 更多