Assel
Assel

Reputation: 31

How can I add my own messages about an error in assert() in C?

I need to get an output with the assertion failing like this:

Assertion failed!
Program: C:\...\assert-test.exe
File: C:\...\assert-test.c, Line 21
Expression: denominator != 0.0

Can anyone explain to me how to remove the default error message and create my own? This is how my code looks like:

#if defined(_STDC_LIB_EXT1_) || defined(_MSC_VER)
    #define __STDC_WANT_LIB_EXT1_ 1
    #define SCANF scanf_s
#else
    #define SCANF scanf
#endif

#ifdef NDEBUG
    #define M_Assert(expr) \
        __M_Assert(buffer, __FILE__, __LINE__, #expr)
#else
    #define M_Assert(expr);
#endif // NDEBUG

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


int main() {
    double numerator = 0.0, denominator = 0.0;
    printf("--- Quotient of two numbers ---\n\nEnter the nominator: ");
    if (SCANF("%lf", &numerator) < 1) {
        printf("invalid input\n"); return 1;
    }
    printf("denominator: ");
    if(SCANF("%lf", &denominator) < 1) {
        printf("invalid input\n"); return 1;
    }

    M_Assert(denominator != 0);

    printf ("quotient is %f\n", numerator / denominator);
    return
}

void __M_Assert(char *buffer, char *file, int line, char *expr) {
    if(!expr) {
        buffer[MAX_PATH];
        GetModuleFileName(NULL, buffer, MAX_PATH);
        std::cerr << "Assssertion failed!\n"
        << "/n"
        << "Programm: \t" << buffer << "\n"
        << "File: \t" << file << ", Line " << line << "\n"
        << "\n"
        << "Expression: \t" << expr << "\n";
        abort();
    }
}

So I tried to define NDEBUG to deactivate all assert calls and then define my own assert macro, but nothing works

Upvotes: 1

Views: 304

Answers (1)

Adrian Mole
Adrian Mole

Reputation: 51845

The basic problem with your macro is that, once the passed expr argument is stringified (with the # operator), it is no longer a testable, Boolean expression. Rather, it is a string literal (of type const char*) that gets passed to your assert function, and that will never be NULL (which is what the !expr test is actually checking for, in your code).

You can implement a function that does what you want by adding an extra int (or bool, if you include the <stdbool.h> header) argument and use the value of the expr argument in the macro that calls the function. It is generally good practice to enclose such arguments in parentheses, when using them in macros.

Note also that you don't need the buffer argument, as that can be declared as a local variable (as also mentioned in the comments).

Here is a possible implementation of your assert function.

#include <stdio.h>
#include <stdbool.h>
#include <Windows.h>

#define M_Assert(expr) \
        MyAssert(__FILE__, __LINE__, (expr), #expr)

void MyAssert(const char* file, int line, bool test, const char* expr);

int main(void)
{
    double numerator = 0.0, denominator = 0.0;
    printf("--- Quotient of two numbers ---\n\nEnter the nominator: ");
    if (scanf("%lf", &numerator) < 1) {
        printf("invalid input\n"); return 1;
    }
    printf("denominator: ");
    if (scanf("%lf", &denominator) < 1) {
        printf("invalid input\n"); return 1;
    }

    M_Assert(denominator != 0);

    printf("quotient is %f\n", numerator / denominator);
    return 0;
}

void MyAssert(const char* file, int line, bool test, const char* expr) {
    if (!test) {
        char buffer[MAX_PATH];
        GetModuleFileName(NULL, buffer, MAX_PATH);
        fprintf(stderr,
            "Assertion failed!\n\n"
            "Program:   \t%s\n"
            "File:      \t%s\n"
            "Line:      \t%d\n"
            "Expression:\t%s\n",
            buffer, file, line, expr);
        abort();
    }
}

I have done some 'cleaning up' of the code, also, by addressing the points made in the comments on your question, such as not using an identifier that begins with the double underscore, not using the scanf_s function (though your assignment may force you to do this), and using fprintf rather than the C++ std::cerr output stream.

Upvotes: 2

Related Questions