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?
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");
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!)
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
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!");
For unexpected default case of a switch, an options is
assert(!"message");
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))
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__);
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.
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.
Related
I have a LOG(fmt, ...) macro that does not work when using a char buf[] as fmt.
The code below is a complete (not actually) working example of the code. In some_function(), I am trying to use LOG() in two different ways but only the first approach works.
To solve the problem, I have tried using #define LOG_STR(x) #x in the following way:
To stringify what is received in the #define LOG by applying LOG_STR() to format like this: LOG_STR(format); and
To apply LOG_STR() directly to the printing like this: LOG(LOG_STR(fmt), 6).
Neither approach works and in fact I get segfault out of it.
#include <stdio.h>
#define LOG(format, ...) do { \
fprintf(stderr, "[LOG] " format " [%s]\n", \
##__VA_ARGS__, __func__); \
} while (0)
static void some_function()
{
// This works
LOG("This is a number: %d", 5);
// This does not work
const char fmt[] = "This is a number: %d";
LOG(fmt, 6);
}
int main(void)
{
some_function();
return 0;
}
When I compile the code above I get the following error:
$ gcc -o log-macro-str log-macro-str.c
log-macro-str.c: In function ‘some_function’:
log-macro-str.c:15:6: error: expected ‘)’ before ‘fmt’
LOG(fmt, 6);
^
log-macro-str.c:4:29: note: in definition of macro ‘LOG’
fprintf(stderr, "[LOG] " format " [%s]\n", \
^~~~~~
I'd like to use LOG() in both ways as done in some_function() or without modifiers and just printing a string. I suspect I might have to stringify the format part but I can't seem to do it correctly.
What am I doing wrong, and how can I solve this issue?
The stringify operator, # in a macro, converts preprocessor tokens to text in a string literal. It will not change the contents of a char buffer to a compile-time string literal.
To make your macro work, use multiple fprintf statements:
#define LOG(format, ...) do { \
fprintf(stderr, "[LOG] "); \
fprintf(stderr, format, __VA_ARGS__); \
fprintf(stderr, " [%s]\n", __func__); \
} while (0)
Sometimes I have to send the result of an assert over canbus, sometimes its local.
I use C only, Embitz compiler using GCC, STM32F407 or STM32F103.
My present assert is:
.h file:
extern char *astrbuf;
#define assert(left,operator,right)\
if(!((left) operator (right))) \
{asprintf(&astrbuf,"\nAssert error %s %d %ld %ld\n",__FILE__, __LINE__,\
(u32)(left),(u32)(right));\
asserted();\
}
.c file:
void asserted(void)
{ dprint("%s",astrbuf);
followed by the display code or canbus code.
Example:
assert(millis,<,maxtime);
This works very well, but will be better if the operator can be indicated.
I simply do not see how to display or send the operator, which can be ==, <, or >.
Why not use the standard assert interface and include the whole expression?
#define assert(EXPR) \
if (!(EXPR)) \
{asprintf(&astrbuf, "\nAssert error %s %d %s\n",__FILE__, __LINE__, #EXPR); \
asserted(); \
}
... using the # macro stringification operator.
By the way, why is half of your code in the macro and the other half in the asserted function? Why not do it all in one place?
#define assert(EXPR) \
if (!(EXPR)) \
{ \
asserted(__FILE__, __LINE__, #EXPR); \
}
with
void asserted(const char *file, int line, const char *expr) {
char *astrbuf;
asprintf(&astrbuf, "%s: %d: assertion failed: %s\n", file, line, expr);
dprint("%s", astrbuf);
...
}
Now you don't need a global variable anymore.
There's another potential issue. If you use your macro like this:
if (foo())
assert(x > 42);
else
bar();
... the else bar(); part will attach to the if statement hidden in assert, not the outer if. To fix this, you can wrap the whole thing in a do while loop:
#define assert(EXPR) \
do { \
if (!(EXPR)) { \
asserted(__FILE__, __LINE__, #EXPR); \
} \
} while (0)
Or alternatively make sure the whole macro expands to a single expression:
#define assert(EXPR) \
((void)((EXPR) || (asserted(__FILE__, __LINE__, #EXPR), 0)))
Of course you could also put the conditional logic in the function:
#define assert(EXPR) asserted(!!(EXPR), __FILE__, __LINE__, #expr)
void asserted(int cond, const char *file, int line, const char *expr) {
if (cond) {
return;
}
...
}
You can use the stringizing operator # to convert the macro parameter operator to a string #operator:
extern char *astrbuf;
#define assert(left,operator,right)\
if(!((left) operator (right))) \
{asprintf(&astrbuf,"\nAssert error %s %d %ld %s %ld\n",__FILE__, __LINE__,\
(u32)(left), #operator, (u32)(right));\
asserted();\
}
Perhaps you could try a slightly different approach to achieve the same goal.
Instead of passing (left, operator, right) into the macro, try passing a single boolean condition. You can use the condition inside of your actual assert function and also stringify it using macros. This way you can still report the whole condition to your debug module (canbus).
This will also work for more complicated expressions like ((a-b)< 0)
#define assert( condition ) custom_assert( condition , STRINGIFY_CONSTANT( condition ), __FILE__, __LINE__)
The stringify macro is in its own header file and was derived based on this link. https://gcc.gnu.org/onlinedocs/gcc-3.4.3/cpp/Stringification.html
#define STRINGIFY_CONSTANT(a) STRINGIFY_CONSTANT_DO_NOT_USE(a)
#define STRINGIFY_CONSTANT_DO_NOT_USE(a) #a
Obviously, don't use STRINGIFY_CONSTANT_DO_NOT_USE
void custom_assert( int condition , const char * condition_string, const char * file_name, int line_number)
{
if (!condition)
{
dprint("Assert Failed:'%s' File:'%s' Line:'%d'",condition_string, file_name, line_number);
}
}
I would avoid putting anything more than a single function call into your assert #define as that can be hard to debug and it will also increase the size of your code. I recommend putting any logic into the function.
I called my assert custom_assert. I also have many #defines to put the debug output to different channels like usb, rs232, a on screen display, etc. In release mode the asserts just reboot the embedded device, which is acceptable in my application.
Assert is a macro, the way I understand it, it is always inline.
The code for the machine has lots of asserts to prevent damage, therefore one needs to keep the code as fast as possible, ie. inline under normal circumstances.
When anything goes wrong, the function asserted is used, speed is no more a problem, safety is. The function asserted switches off motors, etc, and reports over canbus or local display. No way I want to do all that in a macro.
That is why part of the code is in a macro, part in a function.
Please correct me if my understanding is wrong.
Not having a global variable is a definite plus, and I have added the while (0), as in other macros.
I currently have a bunch of debug macros (hijacked from Zed's book Learn C The Hard Way) and I'm trying to compile them on AIX. The macros:
#ifndef __dbg_h__
#define __dbg_h__
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef NDEBUG
#define debug(M, s ...)
#else
#define debug(M, s ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ## s)
#endif
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
#define log_err(M, s ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ## s)
#define log_warn(M, s ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ## s)
#define log_info(M, s ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ## s)
#define check(A, M, s ...) if(!(A)) { log_err(M, ## s); errno=0; goto error; }
#define sentinel(M, s ...) { log_err(M, ## s); errno=0; goto error; }
#define check_mem(A) check((A), "Out of memory.")
#define check_debug(A, M, s ...) if(!(A)) { debug(M, ## s); errno=0; goto error; }
#endif
When I compile my project that imports these macros, the AIX CC compiler prints compiler errors with this message, and then exits normally:
"src/dbg.h", line 13.19: 1506-211 (S) Parameter list must be empty, or consist of one or more identifiers separated by commas.
It prints one of these to every line in the project that use one of the macro functions.
I've tried setting #pragma langlvl (stdc99) and #pragma langlvl (extc99) as advised in this article with no success.
I've also written a small example to see if I can compile it, as follows:
/* file "test.c" */
#include <stdio.h>
#define PRINTERROR(M, s...) fprintf(stderr, "ERROR MSG: " M "\n", ## s)
int main(void) {
PRINTERROR("no args");
PRINTERROR("with args: %s", "foo");
return 0;
}
The compiler emits the following message:
"test.c", line 4.24: 1506-211 (S) Parameter list must be empty, or consist of one or more identifiers separated by commas.
I'm using AIX 5.3 and CC for AIX version 6.0.0.0.
Your code -- either the original version or the edited one, which is using a non-standard extension, see the answer by ouah -- compiles fine for me on AIX 6.1 using XL C/C++ v11.1.
You state that your compiler is CC for AIX version 6.0.0.0. If that is to mean "IBM VisualAge C++ Professional for AIX, V6.0", that version was announced in 2002, i.e. is not really up to date...
Variadic macros in turn were included in the standard only in 1999, so it's quite possible your version of the compiler does not support them yet.
The form:
#define debug(M, s ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ## s)
with s ... is not C but a GNU extension to C. See gcc documentation that states:
If your macro is complicated, you may want a more descriptive name for the variable argument than VA_ARGS. CPP permits this, as an extension. You may write an argument name immediately before the ‘...’; that name is used for the variable argument. The eprintf macro above could be written
#define eprintf(args...) fprintf (stderr, args)
using this extension.
The correct C form for your debug macro would be:
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__,
__LINE__, __VA_ARGS__)
Programs in C that have --verbose or --debug option, how they actually implement it? Without using 3rd party libraries.
My goal is not to do this all the time:
if(debug) printf("Debug msg\n");
printf("Info msg\n");
The most common I've seen is to print to stderr.
#ifdef DEBUG
#define DEBUG_MESSAGE(fmt, ...) fprintf(stderr, fmt ## "\n", __VA_ARGS__)
#else
#define DEBUG_MESSAGE(fmt, ...)
#endif
Elsewhere...
DEBUG_MESSAGE("VERBOSE: %s", "This is a verbose message.");
EDIT
Something that would work at runtime:
#define DEBUG_MESSAGE(fmt, ...)\
do{\
if(g_debugEnabled) fprintf(stderr, fmt ## "\n", __VA_ARGS__);\
}while(0)
Which can be used similarly.
LAST EDIT
Changed to use arbitrary format string with __VA_ARGS__.
You can refer the below program where a macro is defined and based on the option passed to the executable logging is enabled.
#include <stdio.h>
#include <string.h>
#define STREQ(a, b) !(strcmp((a), (b)))
#define logmsg(fmt, ...) \
do { \
if (debug) \
printf(fmt, ##__VA_ARGS__);\
}while(0)
char debug;
int main(int argc, char *argv[])
{
if (argc > 1) {
if ( STREQ(argv[1], "debug"))
debug = 1;
}
logmsg("%s\n", "hello_world");
return 0;
}
Pass debug as the first argument to the executable to enable logging
Note : This program has been tested on Linux with gcc compiler
I'm setting up a trace facility in a large C application. I'll have multiple levels of tracing info that will get emitted using calls to a function that does syslog() emissions.
Any ideas on how I could build a macro that would wrap the test to invoke the function based on the trace level in effect? trace level is an integer bitflag.
Each higher level would incorporate each lower levels trace message type. ie: low/med/high...with high set, it would also emit med/low message types as well.
So that macro would have to do a bitwise OR to see if the current trace setting in effect incorporate the trace directive at each successive trace statement.
ideas??
Here is an idea for a general scheme:
File log.h:
#ifndef LOG_H
#define LOG_H
#include <stdio.h>
typedef enum
{
LOG_LEVEL_ERROR,
LOG_LEVEL_WARN ,
LOG_LEVEL_INFO ,
LOG_LEVEL_DEBUG,
}
log_level_e;
extern log_level_e log_level;
#define LOG(LEVEL,...) \
do \
{ \
if (log_level >= LOG_LEVEL_##LEVEL) \
printf(__VA_ARGS__); \
} \
while (0)
#endif
File log.c:
#include <log.h>
log_level_e log_level = LOG_LEVEL_WARN; // for example
Any other source file:
#include <log.h>
void func() // for example
{
LOG(ERROR,"Error: %d %s\n",1,"ab"); // will be printed
LOG(WARN ,"Warn: %d %s\n",2,"cd"); // will be printed
LOG(INFO ,"Info: %d %s\n",3,"ef"); // will not be printed
LOG(DEBUG,"Debug: %d %s\n",4,"gh"); // will not be printed
}
If you want to have different logging-levels for different modules in your code, then you can use this:
typedef enum
{
LOG_MODULE_X, // for example
LOG_MODULE_Y, // for example
...
LOG_NUM_OF_MODULES
}
log_module_e;
extern log_level_e log_level[LOG_NUM_OF_MODULES];
#define LOG(LEVEL,MODULE,...) \
do \
{ \
if (log_level[LOG_MODULE_##MODULE] >= LOG_LEVEL_##LEVEL) \
printf(__VA_ARGS__); \
} \
while (0)
Please note that in a multi-threaded application, you will have to replace each call to printf with a call to a function that sends the arguments in a message to a designated thread, which will perform the calls to printf in a sequential manner (this is true regardless of whether or not you use a logging system).
Here is how you can prepare and send each message:
void send_msg_to_log_thread(const char* data,...)
{
char msg[MAX_SIZE_OF_LOG_MSG];
va_list args;
va_start(args,data);
vsnprintf(msg,MAX_SIZE_OF_LOG_MSG,data,args);
va_end(args);
// Now, send the 'msg' buffer to the designated thread
}