0

I'm using this statement now to switch between small and slightly more extensive error messages in my C code:

#ifdef COMPACTC
  error_code ((uint16_t) init_cascade, 5);
#else
  error_message (__func__, "cascades malloc failed");
#endif

(it's part of an embedded C code library, so I often don't have the memory available to store the error message strings).

In the first case (COMPACTC defined) I output only a function address and and error number. In the second case I output the full function name and a human-readable error message.

Since I'm copying this snippet all over my code now, I hope I can replace it with a single macro, which I can use like this:

error (init_cascade, "cascades malloc failed", 5)

and provides the correct C code depending on COMPACTC being defined or not.

Maybe it's even possible to have the current function (or some unique identifier) automatically derived from the current location, though I think the preprocessor doesn't know which function's scope it's currently in.

Another improvement would be if a unique error code (5 in this case, which is based on the return value) could be automatically generated from the error message (like a hash value or something).

Then the macro call could be as simple as this:

error ("cascades malloc failed")

Of course, when using hashes, I would need some sort of reference (file/comment) to its original message.

Context: error messages on AVR 8-bits MCU

About the context of this question: This code is written for the ATmega168 (having only 2k of RAM), and AFAIK there's no good/recent emulator available for Linux. So I'm trying to find a good way to produce error messages/codes without the strings eating all of my memory.

Alternative: C function?

A completely different, probably more flexible solution would be to define a C function error (function, message, code) and move the #if/#else/#endif construction to its body. I'm not sure though whether a string literal is compiled in by gcc if it is referred to in a function call but never used inside the function body.

Edit: I just tested this idea: using a string literal in a call but not in the body still has it added to the executable by gcc, so this "alternative" doesn't seem to work.

Brian Tompsett - 汤莱恩
  • 5,195
  • 62
  • 50
  • 120
Adrian
  • 3
  • 2
  • 1
    For function name you can use `__FUNCTION__ `, and for a somewhat unique id you can use `__LINE__` – Dani Mar 27 '16 at 19:22

2 Answers2

2

This should actually be fairly easy:

#ifdef COMPACTC
#   define COMBINED_ERROR(function, message, size) error_code((uint16_t)function, size)
#else
#   define COMBINED_ERROR(function, message, size) error_message (__func__, message)
#endif

and now you can write:

COMBINED_ERROR(init_cascade, "cascades malloc failed", 5);
JVApen
  • 10,085
  • 3
  • 26
  • 56
0

For the first part I suggest:

#ifdef COMPACTC
#   define error(par1, ...) error_code((uint16_t)par1, __VA_ARGS__)
#else
#   define error(par1, ...) error_message (__func__, par1, __VA_ARGS__)
#endif

With this solution you can define as many params as you like.
For the second requirements consider to use macro to insert specific code. Consider the following macro:

#define CallWithError(fnc, ...) { \
                                  int RetCode = fnc(__VA_ARGS__);  \
                                  if (RetCode)  \
                                      error(init_cascade, "cascades malloc failed", RetCode);  \
                                }

In this case you can use the macro to call the function foo and automatically generate error:

CallWithError(foo, 1, "hello");

This will expand in:

{
    int RetCode = foo(1, "hello");
    if (RetCode)
        error(init_cascade, "cascades malloc failed", RetCode);
}
Frankie_C
  • 4,521
  • 1
  • 10
  • 27