assert() with message
Asked Answered
R

10

62

I saw somewhere assert used with a message in the following way:

assert(("message", condition));

This seems to work great, except that gcc throws the following warning:

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

How can I stop the warning?

Reprimand answered 3/5, 2011 at 9:54 Comment(1)
See this related question.Pestilent
F
99

Use -Wno-unused-value to stop the warning; (the option -Wall includes -Wunused-value).

I think even better is to use another method, like

assert(condition && "message");
Ferrari answered 3/5, 2011 at 10:10 Comment(5)
Nice one, I usually do assert(condition /* message */).Slur
This sometimes gives "Conditional expression is constant" warning in Visual Studio. Any ideas on how to remove the warning without suppressing it?Reger
@Samaursa: you probably have an issue with plain condition. Does the compiler also warn with just assert(condition);?Ferrari
It does not. The interesting thing is that OP's original problem code is the solution to VS's warnings! assert((Msg, Cond)); works without warnings on VS 2008.Reger
assert((<cond>) && "msg"); causes CppCheck (v1.90) to generate an "incorrectStringBooleanError" warning.Autocratic
P
23

Try:

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

use as such:

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

Will execute the block only when assert fails.

IMPORTANT NOTE: This method will evaluate expression x twice, in case x evaluates to false! (First time, when the for loop is checking its condition; second time, when the assert is evaluating the passed expression!)

Perth answered 9/6, 2012 at 8:20 Comment(5)
The nice thing about this is that you can omit the message if you want by using assert__(foo); and the semicolon will end the block.Horsefaced
Such implementation will not work if (x) returns true only once: string("a") a; assert__(a.append("b") == "ab") { ... }Ambient
Why for and not if?Composite
This does not seem to work in GCC. Failing assert stops the program execution and printf is not called.Crackpot
@vil It is not possible for assert to stop the program before printf because assert is not called until after printf.Rackrent
C
13

If you want to pass a formatted message, you could use the following macros:

#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); }

Then use it like 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...

Output:

[ERROR] (../src/webserver.c:180: errno: Address already in use) [Server] Failed to bind to port 8080: webserver: ../src/webserver.c:180: server_run: Assertion `(self->socket = u_open(self->port)) != -1' failed.

Based on http://c.learncodethehardway.org/book/ex20.html

Chlorosis answered 29/3, 2014 at 14:57 Comment(1)
This, unfortunately, isn't portable. C99 requires that you use at least one of the optional arguments in a variadic macro (e.g this: assertf(x == y, "x does not equal y") violates the standard. This is easily rectified via assertf(x == y, "%s", "x does not equal y") however). It also relies on the gcc extension ##__VA_ARGS__ which isn't necessarily a bad thing, but it does make it less portableChiquia
T
4

By tradition, (void) communicates to the compiler that you are knowingly ignoring an expression:

/* picard.c, TNG S6E11. */
#define assertmsg(x, msg) assert(((void) msg, x))
assertmsg(2+2==5, "There! are! four! lights!");
Thurible answered 11/11, 2019 at 10:2 Comment(0)
I
2

I like to do it this way in C. This allows calling assert the following ways:

assert(expression);
assert(expression, "reason");
assert(file, "cannot open %s", filename);

Here is the code:

#define assert(cond, ...) \
  if (!(cond)) \
    _assert(#cond, __FILE__, __LINE__, #__VA_ARGS__ __VA_OPT__(,) ##__VA_ARGS__)

void _assert (const char* snippet, const char* file, int line, const char* message, ...)
{
  print("assert failed %s:%d %s\n", file, line, snippet);
 
  if (*message)
  {
    va_list arg;
    va_start(arg, message);
    char* data = va_arg(arg, char*);
    vprintf(data, arg);
  }
}
Incommunicado answered 19/3 at 0:17 Comment(0)
I
1

For unexpected default case of a switch, an options is

assert(!"message");
Impignorate answered 8/5, 2021 at 2:31 Comment(3)
This seems to be always false. Where is the condition that is being tested?Crackpot
This useful for unexpected default case of a switch.Impignorate
That, while true, doesn't have anything to do with the original question.Lief
U
0

A function that takes const char* and returns true would probably save you from all sorts of warnings:

#include <assert.h>

int always_true(const char *msg) {
    return 1;
}

#define assert_msg(expr, msg) assert((expr) && always_true(msg))
Unicycle answered 29/3, 2020 at 3:56 Comment(2)
Definitely not from "unused parameter" warnings.Haik
That's easy to fix: just (void*)msgBionics
M
0

In my case, I changed @pmg's answer to be able to control the output. The (... && "message") didn't work for me.

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

#define __DEBUG__ 1

assert ((1 == 1) && 
       (__DEBUG__ && printf("  - debug: check, ok.\n")) || !__DEBUG__);
Mamelon answered 20/5, 2021 at 11:31 Comment(1)
Try NDEBUG instead of __DEBUG__. It's the standard way to do this as defining NDEBUG automatically disables all assets.Rackrent
S
-1

You could write your own macro that provides the same usage of _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

I also have a macro warn_bug() that prints the name of the program, the file, the line, the function, the errno value and string, and a user message, even if asserts are disabled. The reason behind it is that it won't break the program, but it will warn that a bug will probably be present. You could just define assert_msg to be empty if defined(NDEBUG), though.

Salient answered 24/9, 2019 at 9:10 Comment(0)
S
-11

According to following link http://www.cplusplus.com/reference/clibrary/cassert/assert/

assert is expecting only expression. May be you are using some overloaded function.

According to this, only expression is allowed and thus you are getting this warning.

Standish answered 3/5, 2011 at 10:13 Comment(2)
The inner parenthesis make it ok: assert( ("message", condition) ); This is C: no overloading.Ferrari
Don't see what relevance a C++ website has to a C question.Clapperclaw

© 2022 - 2024 — McMap. All rights reserved.