Structured Exception Handling and MinGW - c

I want to catch a system exception "ACCESS_VIOLATION" from my native code, in MS VS I do this:
#define PROTECTED_START() __try { \
#define PROTECTED_END(ONERR) } __except(EXCEPTION_EXECUTE_HANDLER) {ONERR;}
What is the equivalent in mingw?
I tried this and is not working:
#define PROTECTED_START() __try1(EXCEPTION_DISPOSITION) { \
#define PROTECTED_END(ONERR) } __except1 { ONERR; }

Related

#define new macros inside the #define macro function

#define RB3_SetHigh() do { LATBbits.LATB3 = 1; } while(0)
#define RB3_SetLow() do { LATBbits.LATB3 = 0; } while(0)
#define SET_ALIAS(new_name, old_name) { \
#define new_name##_SetHigh() old_name##_SetHigh() \
#define new_name##_SetLow() old_name##_SetLow() \
}
SET_ALIAS(MOTOR,RB3)
I am trying to change the prefix of an already-defined function macro. I want to rename the MACRO Function in C.
I thought I will use another MACRO Function and will use the MACRO concatenation to achieve this. But it is not allowed. There are my functions that I want to change in the code.

remove debug strings in release build

I use a LOG_DEBUG function to print debug information to the screen. I used a #define _DEBUG to disable LOG_DEBUG function by defining _DEBUG FLAG in compile time (release time). but linux strings commands of release build app still shows debug strings which exists in the compiled app. so what is the alternatives to eliminate arguments of LOG_DEBUG?
#ifdef _DEBUG
#define LOG_DEBUG(fmt, ...) printf("[D][%s:%d %s]", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#else
#define LOG_DEBUG(fmt, ...)
#endif
LOG_DEBUG("this is a debug string"); // "this is a debug string" exists in app release build yet
the compiler I use: ARM/Thumb C/C++ Compiler, RVCT3.1 [Build 569]
optimization: -O3
You could try using stringification:
#include <stdio.h>
#define _DEBUG
#ifdef _DEBUG
#define LOG_DEBUG(str) do { printf("[D][%s:%d %s] ", \
__FILE__, \
__LINE__, \
__FUNCTION__); \
puts(#str); } while(0)
#else
#define LOG_DEBUG(str)
#endif
int main() {
LOG_DEBUG(this is a debug string);
return 0;
}
Note: I tested this in clang, which doesn't exhibit the behaviour you described.

Enable/Disable LOG levels using C Macro

#include <stdio.h>
#define LOG_D(x) { printf("D:"); printf(x);}
#define LOG_E(x) { printf("E:"); printf(x);}
void test(void)
{
LOG_D("ALL is well " );
}
I have a very huge code it has different levels of log, like above code.
In the final tested library I just need only one error logs in order to reduce the code size .
so I want something like this
#define ENABLE_DEBUG_LOG 0
#define ENABLE_ERROR_LOG 1
#define LOG_D(x) {#if(ENABLE_DEBUG_LOG==1) printf("D:"); printf(x); #endif}
#define LOG_E(x) {#if(ENABLE_ERROR_LOG==1) printf("E:"); printf(x);#endif}
I added this #if(ENABLE_DEBUG_LOG==1) just for explaining, I need some solution which can compile.
Another option - you can just comment / uncomment ENABLE_DEBUG_LOG and ENABLE_ERROR_LOG to disable / enable corresponding log level.
// #define ENABLE_DEBUG_LOG // disable DEBUG_LOG
#define ENABLE_ERROR_LOG // enable ERROR_LOG
#ifdef ENABLE_DEBUG_LOG
#define LOG_D(x) { printf("D:"); printf(x);}
#else
#define LOG_D(x) // nothing
#endif
#ifdef ENABLE_ERROR_LOG
#define LOG_E(x) { printf("E:"); printf(x);}
#else
#define LOG_E(x) // nothing
#endif
You cannot nest preprocessor directives. But you can make two versions of your macro and define them in exclusive parts of an #if or #ifdef:
#define ENABLE_DEBUG_LOG 0
#if ENABLE_DEBUG_LOG != 0
#define LOG_D(...) printf("D: " __VA_ARGS__)
#else
#define LOG_D(...) // Do nothing
#endif
Here, the disabled version just "eats" the LOG_D macro and doesn't do anything. (Note that undefined macros are treated as the value 0 in #if conditionals.)
You should be able to do something like this:
#if ENABLE_DEBUG_LOG == 1
# define LOG_D(x) { printf("D:"); printf(x);}
#else
# define LOG_D(x)
#end
That way the debug log statements will just disappear if ENABLE_DEBUG_LOG is undefined or has a different value.
Regarding the other answers, it is not good idea to define the macros completely empty when they are not enabled, as this would go wrong when error logging is enabled:
if (some_error)
LOG_E("Oops...");
do_something();
If LOG_E(x) expands to nothing, then do_something() would only be called if some_error is true, which is probably not what you want!
So you could define the "do nothing" variant of LOG_E(x) like this:
#define LOG_E(x) { }
Rather than starting and ending with braces, I tend to use the do { blah; } while (0) construct as it forces you to put a semicolon on the end when you use it. Something like this:
#if ENABLE_ERROR_LOG
#define LOG_E(x) do { printf("E:"); printf(x); } while (0)
#else
#define LOG_E(x) do ; while (0)
#endif
Then,
if (some_error)
LOG_E("Oops")
would result in a syntax error because of the missing semicolon, forcing you to write it as
if (some_error)
LOG_E("Oops");
Another thing you can do is concatenate the "E:" or "D:" tag with the passed in string, although this requires the parameter to be a string literal, rather than a general char *:
#define LOG_E(x) printf("E:" x)
Another thing you can do is to define the macro with a variable number of parameters (a variadic macro) to increase your options:
#define LOG_E(...) printf("E:" __VA_ARGS__)
Then you can do:
if (some_error)
LOG_E("Oops, got error: %d\n", some_error);
Another thing you can do is let the compiler optimize out the call to printf and define it like this:
#define LOG_E(...) do if (ENABLE_ERROR_LOG) printf("E:" __VA_ARGS__); while (0)
A decent compiler will notice that the if condition is constant and either optimize out the call to printf completely (if the constant condition is false), or include it (if the constant condition is true). For some compilers, you might need to suppress warnings about constant conditions in an if statement.
I am not sure if this is what you want, but you could check the #ifdef directive.
#include <stdio.h>
/* #define DEBUG */
#ifdef DEBUG
#define LOG_D(x) { printf("D: %s\n",x); }
#define LOG_E(x) { printf("E: %s\n",x); }
#else
#define LOG_D(x)
#define LOG_E(x)
#endif
int main() {
LOG_D("blah...");
return 0;
}
If you uncomment the #define DEBUG line, the program will print D: blah...

using macros with various trace levels

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
}

assert() with message

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.

Resources