C89中assert宏的实现,如何退出程序?

assert macro implementation in C89, how to exit the program?

我正在尝试在 C89 标准中实现我自己的 assert 宏。

我希望它和原来的一模一样:

dir/file.c:20: MyFunction: Assertion `null != pointer` failed.

有2个问题:

  1. 没有打印函数名称的选项,因为预标识符 __FUNC__ 仅在 c99 标准后可用。
  2. 我不知道如何退出程序。我尝试了 exit(1)__Exit(1) 但它们都不起作用,我认为这是因为 macros 在每个处理阶段被转换为代码,这意味着预处理器没有甚至还不知道这些 exit 函数是什么。因为它们只在编译阶段相关,对吧?

这是我的代码:

/********************************* Inclusions *********************************/
#include <stdio.h>  /* printf, NULL */

/***************************** Macros Definitions *****************************/
#define ASSERT(expr) \
    if (!(expr)){ \
        fprintf(stderr, "%s:%d: Assertion `%s` failed.\n" \
                ,__FILE__, __LINE__, #expr); }

/******************************************************************************/
int main()
{
    void *null_ptr = NULL;
    
    ASSERT(NULL != null_ptr);
    
    printf("ALL WORKS");
    
    return (0);
}

/******************************************************************************/

我的输出是:

`file.c:25: Assertion `NULL != null_ptr` failed.`

有没有办法获取函数名或者用宏退出程序? 因为现在,我没有得到函数的名称,更重要的是,即使断言打印错误消息,程序也没有停止。

这很奇怪,因为不可能获取函数名称或使用宏退出程序,但原始 assert 可以做到这两个?

P.S __FILE__ 每个标识符只为我打印文件名,如 file.c 而不是 dir/file.c 原始 assert 那样。这是为什么?

我希望我能写这样的东西:

#define ASSERT(expr) \
        if (!(expr)){ \
            fprintf(stderr, "%s:%d: %s: Assertion `%s` failed.\n" \
                    ,__FILE__, __LINE__, __FUNC__, #expr); exit(1) }

谢谢。

  1. 确实,C89没有办法得到函数名。所以如果你只能依赖 C89,你将不得不没有它。请注意,甚至在 C99 之前,许多实现可能已经为此提供了自己的扩展,并且可能已经在他们自己的 assert() 定义中使用了这些扩展;例如GCC 有 __FUNCTION__.

  2. 标准 assert() macro calls abort() 如果断言失败。所以如果你想复制它的行为,你也可以这样做。

Nate Eldredge 回答了您的大部分问题。作为对您 P.S. 的回应,我怀疑这是编译器可以在内部做而我们做不到的事情。与函数名称相同,但没有 __func__(尽管 GCC 有一个 __FUNCTION__ 宏,您可以使用)。

尽管如此,您仍然可以使 assert 更接近编译器 assertassert 试图尽可能地模拟一个函数。因此,首先,它必须作为一个表达式来工作,而你的表达式却不能,因为 if。此外,它应该 return voidman page on assert 给出了这个“原型”:

void assert(scalar expression);

这两种都有可能。这是我刚刚制作的 assert(我认为)设法满足这两个要求:

#define ASSERT(expr)                                                        \
    ((expr) ?                                                               \
        (void) 0 :                                                          \
        (void) (fprintf(stderr, "%s:%d: %s: Assertion `%s` failed\n",       \
                        __FILE__, __LINE__, __FUNCTION__, #expr), abort()))

这利用了 __FUNCTION__ GCC 扩展,您可以根据需要删除它。