I'm developing an embedded application that uses a library for interfacing with a SPI NAND memory chip. The library provided uses a print function in which I, as the applications developer, must override for my specific platform.
For instance, they use the function printf_ extensively in their code.
I redefine it as such, to get the print function to print over the serial interface
#define printf_(...) serial.printf(__VA_ARGS__)
It works fine, except that on this platform, you need to supply a carriage return ("\r") for a newline. So right now, when the library is called, the formatting is horrible.
I'd like to append a "\r" to the end of whatever is supplied to the print function. Like
#define printf_(...) serial.printf(__VA_ARGS__##"\r")
Obviously that doesn't work.
I'm really not familiar with, and have sort of a hard time understanding variadic functions in C, so this would provide me with a little learning opportunity if I could figure this out, or at least I would learn if this is not possible.
I also can't just wrap the function using va_lists and vsprintfs because my platform does not support this (and I'd rather redefine it in a macro, as a performance/stylistic choice, personally).
Is there a way to do this?
Perhaps you could just output '\r' after the call to serial.printf ?
#define printf_(...) do { serial.printf(__VA_ARGS__); serial.printf("\r"); } while(0)
I agree with other users that your requirement of CR coming after LF is quite strange, and I have a strong suspicion you mean for it to be CRLF, not LFCR. Regardless, I will help you with your original requirement of appending CR to the string.
It is going to be incredibly difficult to perform this operation in a one-liner macro. Alternatively, you could use a nasty-looking multi-line macro:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define printf_(format, args...) \
do { \
int _len_orig = strlen(format); \
/* strlen doesn't consider newline. Check for that. */ \
if ( format[_len_orig] == '\n' ) \
_len_orig++; \
\
/* len_orig + 2 to make space for null terminator and '\r' */ \
unsigned _new_size = _len_orig + 2; \
char* _new_str = calloc(_new_size, 1); \
strncpy( _new_str, format, _len_orig ); \
_new_str[_new_size-2] = '\r'; \
\
/* Print out the raw hex of the string to prove it worked */ \
int _i; \
for( _i = 0; _i < _new_size; _i++) \
printf("%02x ", _new_str[_i]); \
printf("\n"); \
free(_new_str); \
} while(0)
int main(){
char* str = "####\n";
printf_( str );
return 0;
}
In my macro, I have not used your serial.printf function but rather made some short code that prints out the hexidecimal values of the concatenated string for proof that the logic works.
Explanation
Macros are required to appear as a single line to the C Preprocessor. The additions of \ at the end of each macro line escape the newline character.
gcc allows for named arguments in your macro. Here, format describes the format string you would normally pass to printf, and args... is the variable argument name for "everything else" you would pass into printf. I do not reference args in this example, but you will certainly want to modify my example in your final code to include it. Your call to printf would look something like serial.printf( _new_str, args);
Multi-line macros are kind of nasty in that you need to do some trickery to get them to appear as normal functions to the human programmer. The need for enclosing the macro in a do-while is nicely discussed here. The linked page is meant for C++, but it applies to C as well.
If you copy my code, compile, and run it, this is the output:
[clipp#h2ologin3:~]$ ./a.out
40 40 40 40 0a 0d 00
Here, this ASCII dump is showing us that 4 # symbols were copied, followed by \n, \r, and finally \0.
There is also a strong case for instead writing this as an inline C function. You say that your system doesn't support va_list etc. so if that is true, then a macro may be the only choice.
QED.
Related
My goal is to print the filenames and not relative path to the filename. I'm experimenting with it using the macro TRACE().
Since it's all in the same file, I'm simulating the filename as an input to TRACE(). So in real life, you could say the inputs are replaced with __FILE__.
Code:
#include <stdio.h>
#include <string.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define __FILENAME__(x) TOSTRING(strrchr(x, '\\'))
#define TRACE(s, ...) \
{ \
if (strrchr(s, '\\')) { \
static const char str[] = __FILENAME__(s) "\n\r"; \
printf(str, ##__VA_ARGS__); \
} else { \
static const char str[] = s "\n\r"; \
printf(str, ##__VA_ARGS__); \
} \
}
int main() {
TRACE("file.c");
TRACE("parent\\file.c");
return 0;
}
Output:
file.c
strrchr("parent\\file.c", '\\')
So if it's local file, it's printed as file.c, which is great. This means the ifcase in the macro is working :). But when it's a file in another folder, I fail to "stringify" the computation strrchr(s, '\\'). Why?
Furthermore, I don't see an issue with the computation in the define, since everything is defined at compile time!! (That's why the if case is working, right?)
If I remove the TOSTRING() from __FILENAME__ I get loads of errors instead. Because it fails to concatenate the output of __FILENAME__ with str[]
Is there a way to solve this?
Preliminary observations
Note that in C (as opposed to C++), you can't initialize a static const char str[] array with the result of a function call. If the strrchr() found a backslash, you probably want to print the name from one after the backslash. And the stringification isn't going to stringify the result of invoking strrchr().
Also note that you should not create function or variable names that start with an underscore, in general. C11 §7.1.3 Reserved identifiers says (in part):
All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
See also What does double underscore (__const) mean in C?
Since the first argument to your TRACE macro is already a string, there's not much benefit to applying the stringification — unless you want the double quotes to appear when the name is printed.
Simple adaptation
To get more or less the result you want, you would need to accept that there'll be run-time overhead invoking strrchr() each time you pass the trace (or a more elaborate scheme for initialization), along the lines of:
#define TRACE(s, ...) \
do { \
const char *basename = strrchr(s, '\\'); \
if (basename == 0) \
basename = s; \
else \
basename++; \
printf(basename, ## __VA_ARGS__); \
} while (0)
The do { … } while (0) idiom is standard; it allows you to write:
if (something)
TRACE("hocuspocus.c: test passed\n");
else
TRACE("abracadabra.c: test failed\n");
If you use the braces-only notation in the question, the semicolon after the first TRACE makes the else into a syntax error. See also C #define macro for debug printing and Why use apparently meaningles do { … } while (0) and if … else statements in macros? and do { … } while (0) — what is it good for?
The ## __VA_ARGS__ trick is fine as long as you know that it is a GCC (and Clang because it is compatible with GCC) extension, and not a part of standard C.
It also isn't entirely clear how you plan to use the variable arguments. It looks as though you'd be able to do:
TRACE("some\\kibbitzer.c: value %d is out of the range [%d..%d]\n",
value, MIN_RANGE, MAX_RANGE);
where the file name is embedded in the format string. Maybe you have in mind:
TRACE(__FILE__ ": value %d is out of the range [%d..%d]\n",
value, MIN_RANGE, MAX_RANGE);
That can work; __FILE__ is a string literal, unlike __func__ which is a predefined identifier (static const char __func__[] = "…function name…";).
Finally (for now), consider whether trace output should go to standard output or to standard error. It is easily arguable it should go to standard error; it (probably) isn't part of the regular output of the program.
I recommend looking at the 'debug macro' question and answer — but I am biassed since I wrote the top-scoring answer.
Reducing runtime overhead
You can reduce the runtime overhead to a single call to strrchr() per file name, as long as you aren't messing with automatic variables etc. You'll be OK if you're using string literals.
#define TRACE(s, ...) \
do { \
static const char *basename = 0;
if (basename == 0) \
{
if ((basename = strrchr(s, '\\')) == 0) \
basename = s; \
else \
basename++; \
} \
printf(basename, ## __VA_ARGS__); \
} while (0)
This initializes the basename to null; on the first pass through the code, basename is set to the correct position in the string; thereafter, there is no further call to strrchr().
Warning: the code shown has not been compiled.
I think there is some issue with the understanding of how macros and functions work.
Macros are not "executed", they are just simple text substitution. Yes, that happens in the compile time (actually pre compiling), but just the substitution.
Macros won't execute and code or call any functions (like strrchr) while compiling.
In your code you have -
#define __FILENAME__(x) TOSTRING(strrchr(x, '\\'))
Whenever __FILENAME__(foo) is used, it is replaced with "strrchr(foo, '\\')". I am sure this is not what you want.
Personally, I don't see any reason for using macros here. Just make it into a normal function. The compiler will optimize it for you.
Is there a general method to shield comments in macro arguments in C? I know that parentheses can be used for this purpose, but that will not work in cases where added parentheses result in syntax errors in the macro output. I've heard that ({ }) works to shield commas in GCC, but I need this code to also work in VC++ (one of the recent versions which does conform to the C standard with regard to commas in macros). I also cannot use variadic macros in my case.
The specific case I'm trying to do is this (lengthof is a macro defined elsewhere). I'm trying to write a single macro for the entire thing because this will be used many times, and having a multi-macro solution would add a large amount of additional testing code.
#define TEST_UNFUNC(func, res_type, res_set, op_type, op_set) \
{ \
static const res_type res[] = res_set; \
static const op_type op[] = op_set; \
int i; \
for (i = 0; i < MIN(lengthof(res), lengthof(op)); i++) \
assert(func(op[i]) == res[i]); \
}
If possible I would like a general answer and not merely a workaround specific to this particular macro.
Use parentheses to shield the comma, and then pass them through a special unparen macro, defined in the example below:
#include <stdio.h>
#define really_unparen(...) __VA_ARGS__
#define invoke(expr) expr
#define unparen(args) invoke(really_unparen args)
#define fancy_macro(a) printf("%s %s\n", unparen(a))
int main()
{
fancy_macro(("Hello", "World"));
}
The trick here is that the invoke macro forces an extra expansion, allowing really_unparen to be called even though it's not followed by parentheses in the source.
Edit: per comment below, this appears to not be necessary in this case. Though I'm sure I've hit a case where I needed it sometime ... and it doesn't hurt.
I have the following macro function in vanilla C:
#define GLOG(format_string, ...) { \
const char *file = strrchr(__FILE__, '/'); \
char format[256] = "%s:%s!%d\t"; \
strncat(format, format_string, 248); \
strcat(format, "\n"); \
printf(format, __FUNCTION__, file ? file : __FILE__, __LINE__, ##__VA_ARGS__); \
}
which lets me print a debug message containing the current function, file and line number, e.g.
GLOG("count=%d", count);
might print
do_count:counter.c!123 count=456
How can I modify the function to print all local variables if caller omits format_string? e.g.
GLOG();
might print
do_count:counter.c!123 count=456, message="Hello world", array=[7, 8] structure={ptr=0xACE0FBA5E, coord={x=9, y=0}}
If that's not possible, how can I modify it to print just the current function, file and line number? e.g.
do_count:counter.c!123
As is, this returns an error:
error: expected expression before ‘,’ token
as the strncat line is simply
strncat(format, , 248);
First, inspecting all the local variables at runtime by the process itself seems impossible because C doesn't have any means for reflection.
Second, you would be much better off if you wrote the logging macro like that:
#include <stdio.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define GLOGF(fmt, ...) \
printf("%s:%s " fmt "\n", __func__, __FILE__ "!" TOSTRING(__LINE__), ##__VA_ARGS__)
int main (void) {
/* main:test.c!xx count=5 */
GLOGF("count=%d", 5);
/* main:test.c!xx */
GLOGF();
return 0;
}
It is simpler and doesn't incur any additional runtime overhead since the string is concatenated at compile-time.
Also note that I have used __func__ instead of __FUNCTION__, because the latter is non-standard.
I found this link in this answer. It might help you with the first part of the question.
The second, how to get all local variables, is much harder, if not impossible. The reason is that the code, when compiled, doesn't actually have variables, it just have offsets into a memory area (the stack.) It might be possible that your compiler have internal functions that can be used to inspect the stack, but then you only have possible values not the names of the variables. The only solution I see it to use special pre-processor macros to declare local variables, and then a list of structures to represent them for introspection, which will be a lot of both runtime and memory overhead.
As others here have mentioned, C does not have reflection features, and therefore you are not going to be capable of capturing the local variables in a macro call. That being said, if you want something to conditionally happen with a macro depending on if there are or are not any arguments to the macro invocation (i.e., your "non-null" and "null" arguments), then you can do something like the following:
#include <string.h>
#define NULL_IDENT ""
#define IDENT(ident_name) #ident_name
#define MACRO(ident_name) \
if (strcmp(NULL_IDENT, IDENT(ident_name)) == 0) { \
/* add code for a null argument passed to the macro */ } \
else { \
/* add code for a non-null argument passed to the macro */ }
Based on Blagovest Buyukliev's answer, I've come up with the following solution for part 2:
#define GLOG(fmt, ...) do { const char *fn = strrchr(__FILE__, '/'); \
printf("%s:%s!%d\t"fmt"\n",__func__,fn?++fn:__FILE__,__LINE__,##__VA_ARGS__);\
} while(0)
using the preprocessor's string concatenation to simply concatenate a null string if the parameter is omitted.
Additionally, I added the do {...} while(0) to swallow the trailing semicolon so that the following if...else works:
if (...)
GLOG();
else
/* do something else */
(idea from http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html ).
What MACRO can be used to switch off printf statements, rather than removing them all for deployment builds, I just want to switch them off, skip them, ignore them.
EDIT: I personally use gcc, but code is part of a larger project which will be compiled on a Panda board running Ubuntu.
Not exactly what you ask for, but I use this construct in my code for debug output when I do not have a proper logging system handy:
#if 1
#define SPAM(a) printf a
#else
#define SPAM(a) (void)0
#endif
So I can do this all over my code
SPAM(("foo: %d\n", 42));
and then disable all of them by changing 1 to 0 in #if above.
But if you have variadic macro support in all compilers that you write code for, then you may go for other answers and just redefine printf. (That being said, I find it useful to distinct debugging prints from regular ones in code — using a different function name helps readability.)
Note that you also can redirect stdout to the /dev/null, but I assume that you want to get rid from runtime overhead as well.
#ifdef IGNORE_PRINTF
#define printf(fmt, ...) (0)
#endif
See also C #define macro for debug printing which discusses some important issues closely related to this.
Two options, either:
#define printf(...)
(requires C99 variadic macro parameters), you need to put it in some common header file which is never included before stdio.h, if there is one..
Or you can tell the linker to link it to something else, in GCC you would define
int wrap_printf(void) {return 0;}
and link using
--wrap printf
All that said, you should probably not be using printf for printing debug output, but rather a macro or utility function (which in turn can use printf if you'd like) which you have better control over.
Hope that helps.
If you want to avoid the potential warning that Jonathan's answer may give you and if you don't mind an empty call to printf you could also do something like
#define printf(...) printf("")
This works because C macros are not recursive. The expanded printf("") will just be left as such.
Another variant (since you are using gcc) would be something like
inline int ignore_printf(char const*, ...)
__attribute__ ((format (printf, 1, 2)));
inline int ignore_printf(char const*, ...) { return 0; }
#define printf ignore_printf
and in one compilation unit
int ignore_printf(char const*, ...)
I use to prefix the debug printf()s (not all of them) with PDEB.
For the debug builds, I compile with -DPDEB= (nothing)
For the release builds, I compile with -DPDEB="0&&" or -DPDEB="0 && "
That way, the following code (test.c):
#include <stdio.h>
void main(void) {
printf("normal print\n");
PDEB printf("debug print\n");
}
outputs:
either (in release mode):
normal print
either (in debug mode):
normal print
debug print
Ideally, one could aim for turning the PDEB into the "//" (comments mark), except that this is not possible under the standard pre-/processing chain.
Another possibility would be something like freopen("/dev/null", "w", stdout);
This doesn't exactly disable printf though -- it's roughly equivalent to running your program with stdout redirected to /dev/null, like: ./myprog > /dev/null at the shell prompt.
I included #define printf // in common header file. It will suppress all the printf.
Below simple function serves the purpose, I use the same.
int printf(const char *fmt, ...)
{
return (0)
}
Use this macro to enable or disable the printf.
//Uncomment the following line to enable the printf function.
//#define ENABLE_PRINTF
#ifdef ENABLE_PRINTF
#define DEBUG_PRINTF(f,...) printf(f,##__VA_ARGS__)
#else
#define DEBUG_PRINTF(f,...)
#endif
Then call "DEBUG_PRINTF" instead of "printf".
For example:
DEBUG_PRINTF("Hello world: %d", whateverCount);
I have used two macros for this. The first one defines the condition to print. In this simple example we print any time the parameter is not zero. More complex expressions can be used.
The second one determines, based on the first macro, to call or not printf.
If the condition can be determined by the compiler (with the right optimization settings) no code is generated.
If the condition cannot be determined at compile time then will be at run time. One of the advantages of this method is that if printf is not going to happen then the whole printf is not evaluated avoiding many conversions to string that can happen in a complex printf statement.
#define need_to_print(flag) ((flag) != 0))
#define my_printf(debug_level, ...) \
({ \
if(need_to_print(debug_level)) \
printf(__VA_ARGS__); \
})
to use it call my_printf instead of printf and add a parameter at the beginning for the print condition.
my_printf(0, "value = %d\n", vv); //this will not print
my_printf(1, "value = %d\n", vv); //this will print
my_printf(print_debug, "value = %d\n", vv); //this will print if print_debug != 0
the ( ... ) parenthesis surrounding the macro make it a single statement.
As mentioned in many of my previous questions, I'm working through K&R, and am currently into the preprocessor. One of the more interesting things — something I never knew before from any of my prior attempts to learn C — is the ## preprocessor operator. According to K&R:
The preprocessor operator ##
provides a way to concatenate actual
arguments during macro expansion. If a
parameter in the replacement text is
adjacent to a ##, the parameter is
replaced by the actual argument, the
## and surrounding white space are
removed, and the result is re-scanned.
For example, the macro paste
concatenates its two arguments:
#define paste(front, back) front ## back
so paste(name, 1) creates the token
name1.
How and why would someone use this in the real world? What are practical examples of its use, and are there gotchas to consider?
One thing to be aware of when you're using the token-paste ('##') or stringizing ('#') preprocessing operators is that you have to use an extra level of indirection for them to work properly in all cases.
If you don't do this and the items passed to the token-pasting operator are macros themselves, you'll get results that are probably not what you want:
#include <stdio.h>
#define STRINGIFY2( x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#define PASTE2( a, b) a##b
#define PASTE( a, b) PASTE2( a, b)
#define BAD_PASTE(x,y) x##y
#define BAD_STRINGIFY(x) #x
#define SOME_MACRO function_name
int main()
{
printf( "buggy results:\n");
printf( "%s\n", STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
printf( "%s\n", BAD_STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
printf( "%s\n", BAD_STRINGIFY( PASTE( SOME_MACRO, __LINE__)));
printf( "\n" "desired result:\n");
printf( "%s\n", STRINGIFY( PASTE( SOME_MACRO, __LINE__)));
}
The output:
buggy results:
SOME_MACRO__LINE__
BAD_PASTE( SOME_MACRO, __LINE__)
PASTE( SOME_MACRO, __LINE__)
desired result:
function_name21
CrashRpt: Using ## to convert macro multi-byte strings to Unicode
An interesting usage in CrashRpt (crash reporting library) is the following:
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
//Note you need a WIDEN2 so that __DATE__ will evaluate first.
Here they want to use a two-byte string instead of a one-byte-per-char string. This probably looks like it is really pointless, but they do it for a good reason.
std::wstring BuildDate = std::wstring(WIDEN(__DATE__)) + L" " + WIDEN(__TIME__);
They use it with another macro that returns a string with the date and time.
Putting L next to a __ DATE __ would give you a compiling error.
Windows: Using ## for generic Unicode or multi-byte strings
Windows uses something like the following:
#ifdef _UNICODE
#define _T(x) L ## x
#else
#define _T(x) x
#endif
And _T is used everywhere in code
Various libraries, using for clean accessor and modifier names:
I've also seen it used in code to define accessors and modifiers:
#define MYLIB_ACCESSOR(name) (Get##name)
#define MYLIB_MODIFIER(name) (Set##name)
Likewise you can use this same method for any other types of clever name creation.
Various libraries, using it to make several variable declarations at once:
#define CREATE_3_VARS(name) name##1, name##2, name##3
int CREATE_3_VARS(myInts);
myInts1 = 13;
myInts2 = 19;
myInts3 = 77;
Here's a gotcha that I ran into when upgrading to a new version of a compiler:
Unnecessary use of the token-pasting operator (##) is non-portable and may generate undesired whitespace, warnings, or errors.
When the result of the token-pasting operator is not a valid preprocessor token, the token-pasting operator is unnecessary and possibly harmful.
For example, one might try to build string literals at compile time using the token-pasting operator:
#define STRINGIFY(x) #x
#define PLUS(a, b) STRINGIFY(a##+##b)
#define NS(a, b) STRINGIFY(a##::##b)
printf("%s %s\n", PLUS(1,2), NS(std,vector));
On some compilers, this will output the expected result:
1+2 std::vector
On other compilers, this will include undesired whitespace:
1 + 2 std :: vector
Fairly modern versions of GCC (>=3.3 or so) will fail to compile this code:
foo.cpp:16:1: pasting "1" and "+" does not give a valid preprocessing token
foo.cpp:16:1: pasting "+" and "2" does not give a valid preprocessing token
foo.cpp:16:1: pasting "std" and "::" does not give a valid preprocessing token
foo.cpp:16:1: pasting "::" and "vector" does not give a valid preprocessing token
The solution is to omit the token-pasting operator when concatenating preprocessor tokens to C/C++ operators:
#define STRINGIFY(x) #x
#define PLUS(a, b) STRINGIFY(a+b)
#define NS(a, b) STRINGIFY(a::b)
printf("%s %s\n", PLUS(1,2), NS(std,vector));
The GCC CPP documentation chapter on concatenation has more useful information on the token-pasting operator.
This is useful in all kinds of situations in order not to repeat yourself needlessly. The following is an example from the Emacs source code. We would like to load a number of functions from a library. The function "foo" should be assigned to fn_foo, and so on. We define the following macro:
#define LOAD_IMGLIB_FN(lib,func) { \
fn_##func = (void *) GetProcAddress (lib, #func); \
if (!fn_##func) return 0; \
}
We can then use it:
LOAD_IMGLIB_FN (library, XpmFreeAttributes);
LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
LOAD_IMGLIB_FN (library, XpmReadFileToImage);
LOAD_IMGLIB_FN (library, XImageFree);
The benefit is not having to write both fn_XpmFreeAttributes and "XpmFreeAttributes" (and risk misspelling one of them).
A previous question on Stack Overflow asked for a smooth method of generating string representations for enumeration constants without a lot of error-prone retyping.
Link
My answer to that question showed how applying little preprocessor magic lets you define your enumeration like this (for example) ...;
ENUM_BEGIN( Color )
ENUM(RED),
ENUM(GREEN),
ENUM(BLUE)
ENUM_END( Color )
... With the benefit that the macro expansion not only defines the enumeration (in a .h file), it also defines a matching array of strings (in a .c file);
const char *ColorStringTable[] =
{
"RED",
"GREEN",
"BLUE"
};
The name of the string table comes from pasting the macro parameter (i.e. Color) to StringTable using the ## operator. Applications (tricks?) like this are where the # and ## operators are invaluable.
You can use token pasting when you need to concatenate macro parameters with something else.
It can be used for templates:
#define LINKED_LIST(A) struct list##_##A {\
A value; \
struct list##_##A *next; \
};
In this case LINKED_LIST(int) would give you
struct list_int {
int value;
struct list_int *next;
};
Similarly you can write a function template for list traversal.
The main use is when you have a naming convention and you want your macro to take advantage of that naming convention. Perhaps you have several families of methods: image_create(), image_activate(), and image_release() also file_create(), file_activate(), file_release(), and mobile_create(), mobile_activate() and mobile_release().
You could write a macro for handling object lifecycle:
#define LIFECYCLE(name, func) (struct name x = name##_create(); name##_activate(x); func(x); name##_release())
Of course, a sort of "minimal version of objects" is not the only sort of naming convention this applies to -- nearly the vast majority of naming conventions make use of a common sub-string to form the names. It could me function names (as above), or field names, variable names, or most anything else.
I use it in C programs to help correctly enforce the prototypes for a set of methods that must conform to some sort of calling convention. In a way, this can be used for poor man's object orientation in straight C:
SCREEN_HANDLER( activeCall )
expands to something like this:
STATUS activeCall_constructor( HANDLE *pInst )
STATUS activeCall_eventHandler( HANDLE *pInst, TOKEN *pEvent );
STATUS activeCall_destructor( HANDLE *pInst );
This enforces correct parameterization for all "derived" objects when you do:
SCREEN_HANDLER( activeCall )
SCREEN_HANDLER( ringingCall )
SCREEN_HANDLER( heldCall )
the above in your header files, etc. It is also useful for maintenance if you even happen to want to change the definitions and/or add methods to the "objects".
SGlib uses ## to basically fudge templates in C. Because there's no function overloading, ## is used to glue the type name into the names of the generated functions. If I had a list type called list_t, then I would get functions named like sglib_list_t_concat, and so on.
I use it for a home rolled assert on a non-standard C compiler for embedded:
#define ASSERT(exp) if(!(exp)){ \
print_to_rs232("Assert failed: " ## #exp );\
while(1){} //Let the watchdog kill us
I use it for adding custom prefixes to variables defined by macros. So something like:
UNITTEST(test_name)
expands to:
void __testframework_test_name ()
One important use in WinCE:
#define BITFMASK(bit_position) (((1U << (bit_position ## _WIDTH)) - 1) << (bit_position ## _LEFTSHIFT))
While defining register bit description we do following:
#define ADDR_LEFTSHIFT 0
#define ADDR_WIDTH 7
And while using BITFMASK, simply use:
BITFMASK(ADDR)
It is very useful for logging. You can do:
#define LOG(msg) log_msg(__function__, ## msg)
Or, if your compiler doesn't support function and func:
#define LOG(msg) log_msg(__file__, __line__, ## msg)
The above "functions" logs message and shows exactly which function logged a message.
My C++ syntax might be not quite correct.