Using macros to convert print statements - c

I have multiple uses of one type of debug statement in my code - say DEBUG("abcd"); or DEBUG("abc %d def", val) which get translated and printed to a file.
Now, however I want to convert them all to a different type of logging which requires using a function with declaration like -
WRITE(char *string);
Usage: WRITE(L"abcd") etc..
Because the usage of this debug statement is huge, I am hoping to use macros to convert the same. Can this be done; also given that the DEBUG function used to take in format specifiers too?

Maybe you're looking at : #define DEBUG(str,...) WRITE(str,__VA_ARGS__)

You probably want something like the gnu function
int asprintf(char **strp, const char *fmt, ...);
that is a function that returns an allocated string of sufficiently large size in *strp that holds your printed string. Supposing that your WRITE and DEBUG macros are only used in places where they are used as statements and not inside expressions, you could then do
#define DEBUG(...) \
do { \
char* strp = 0; \
asprintf(&strp, __VA_ARG__); \
WRITE(strp); \
free(strp); \
} while(0)
If your platform doesn't have asprintf, you probably can come up with an implementation of it that uses snprintf and enlarges the string to be returned as needed.

Related

Incompatible argument type conversion using macro

I am trying to use a single macro argument (provided by third party) to display a string with placeholders and values of those place holder.
#define DBG1(AR1) do{ \
printf(AR1); \
}while(0);
int main()
{
int varDummy = 123;
/* Expecting Test Message 123*/
DBG1(("Test Message %d\r\n", varDummy));
return 0;
}
Notice the argument of DBG1 ("Test Message %d\r\n", varDummy) is in parentheses and is being treated whole as a string i.e. const char* and error shows up that varDummy not allowed to be converted due to it's int type.
In the actual code the argument of DBG1 has different number of place holders (%d, %x...) and respective values which have to be printed. Apparently I am unable to display the passed string along with its place holder values.
In the real code I have the following macro from third party
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
/* discarding the first argument */
#define LWIP_DEBUGF(debug, message) do{ \
DBG1(message) \
}while(0);
Please note this is a resource constrained embedded system.
Notice the argument of DBG1 ("Test Message %d\r\n", varDummy) is in parentheses …
This problem is at the same time the solution. Since there are already parentheses, you need not supply them in your DBG1 macro and can change printf(AR1); \ to printf AR1; \. Besides that, you can simplify the macro to
#define DBG1(AR1) printf AR1;
(since you can't change the LWIP_DEBUGF macro from third party, we unfortunately have to keep the semicolon).
You can use a temporary buffer to hold the adjointed string, something like this:
#define DBG1(AR1) do{\
printf(AR1);\
} while(0)
#define BUFFER_SIZE 100
int main()
{
int varDummy = 123;
char buffer[BUFFER_SIZE];
sprintf(buffer, "Test Message %d\r\n", varDummy);
/* Expecting Test Message 123*/
DBG1(buffer);
return 0;
}
Notice the argument of DBG1 is in parentheses
Yeah that's the problem, you are calling printf(("Test Message %d\r\n", varDummy)); where the inner parentheses has turned the , from a function argument separator into the comma operator. The comma operator discards the left operand and returns the right. Which is int, a type incompatible with the format string of printf, which explains the compiler error.
Instead you should be using a variadic macro:
#define DBG1(AR1,...) printf(AR1, __VA_ARGS__)
...
DBG1("Test Message %d\r\n", varDummy);
The do-while(0) trick is pointless to use in this case.
Please note this is a resource constrained embedded system.
Then you shouldn't be using stdio.h or variadic functions in the first place. Instead, design your own product-specific logging module. Writing a little snippet that spits out strings on UART isn't rocket science.
Similarly, parsing raw binary data from UART isn't rocket science either, so you don't actually need the string conversion, just a decent terminal program on the PC.

How to pass a string literal to a function with explicit section storage

Please forgive if this has been asked before, but I couldn't find a question like it.
The problem is like this: for a certain microcontroller I need selected string literals to be in another section than the default .rodata section. The "other" section will be put in flash (which can only be read 4 bytes at a time, so it can't be used freely, the function needs to be aware of the fact), while the .rodata section gets copied into ram, which is useful, because ram can be read without alignment restrictions, but it is very limited in size.
The construction I now use is like this:
#define roflash __attribute__((section(".flash.rodata"))) __attribute__((aligned(sizeof(char*))))
static roflash const char literal[] = "text";
(+ modifications in the loader script of course).
This works as intended. But it means for every string handling function I'm calling something like this:
static roflash const char literal[] = "text";
do_something(literal);
The holy grail would be something that can combine both into one "black box" construction, so I can write do_something_roflash("text");
I guess it would be something with a #define and a code block, so the same variable name could be used over and over again. But then I get stuck, because some of the functions have a variable number of arguments, so something like this won't work:
#define function_roflash(s) { \
static roflash const char str[] = s; \
function_roflash_implementation(s); \
}
In fact I guess I'd need a variable-argument #define, does that exist?
Other solutions also very welcome.
Thx.
One idea for a somewhat generic GCC variadic macro is:
#define roflash(func, str, ...) { \
static roflash const char s[] = str; \
func(s, __VA_ARGS__); \
}
With just one macro you could support many functions that accept one string constant as the first parameter:
roflash(printf, "%d", 42);
roflash(do_something, "text");
roflash(obj.write, "text");
roflash(obj->write, "text");

winapi - display int variable value in MessageBox using macros

For debugging purposes I am trying to make a short macros to display various types, instead of constant copying all the MessageBox functions' params.
For strings I have following macros:
#define DEBUG(x) MessageBox(NULL, x,"DEBUG",MB_ICONINFORMATION|MB_OK);
Calling it working great, whether I pass variable (array of char) or direct string.
Now, I try to make the same thing for int. Have defined macros like this:
#define STRIGIFY(x) #x
#define TOSTRING(x) STRIGIFY(x)
#define DEBUGINT(x) DEBUG(TOSTRING(x))
It works only in case I pass direct integer value:
DEBUGINT(742);
However if I pass int variable, MessageBox displays variable name instead of its value:
int count = 3;
DEBUGINT(count);
The thing I find pretty interesting for me is that I can pass literally anything in DEBUGINT macros and it will still work:
DEBUGINT(some unescaped string)
How do I define a macros that would use a variable value instead of its name?
This doesn't answer the question as it was asked, but I'll risk my reputation and suggest a different solution.
PLEASE, do yourself a favor and never use MessageBox() or other modal UI to display debug information. If you do want to interrupt program execution at that point, use the breakpoint; it also allows you to attach the condition, so that you don't need to examine the value manually.
If you do not want the interruption, just print the value to a debug output window using ::OutputDebugString(). That can be seen in the debugger if it is attached, or via DebugView tool.
Another small suggestion (for Visual Studio users): if you prepend your output with a source file name and the code line number, double-clicking on that line in the output window will take you straight to that line. Just use __FILE__ and __LINE__ in your formatted string.
You can't. The preprocessor doesn't know anything about variables or their values, because it doesn't do anything run-time only at compile-time.
You can use variable argument list
#include <stdio.h>
void message(const char* format, ...)
{
int len;
char *buf;
va_list args;
va_start(args, format);
len = _vscprintf(format, args) + 1; //add room for terminating '\0'
buf = (char*)malloc(len * sizeof(char));
vsprintf_s(buf, len, format, args);
MessageBoxA(0,buf,"debug",0);
//OutputDebugStringA(buf);
free(buf);
}
message("test %s %d %d %d", "str", 1, 2, 3);
You might also want to change to unicode version.
You need to "print" the variable to a buffer (array of char) using something like sprintf (or snprintf in VS 2015) and pass the resulting output to MessageBox as the string to be displayed.

__printflike__ modifier

what is "__printflike__ modifier" exactly? what does this term mean?
At a guess it tells the compiler you're using that a function takes arguments in the form [anything, ] format, ... where the format, ... part look like the arguments to printf. The __printflike__ attribute lets the compiler test the types in the argument list against the string format. This comes up when you write a function like log(format, ...) and use vsprintf to subordinate the formatting work to the usual standard library functions before sending the string to some special log interface.
If you are using GCC then it is probably a #define in your project something like:
#define __printflike__ __attribute__((format(printf, 1, 2)))
Where 1, 2 means that format, ... appear in positions 1 and 2.
I have a function in my error reporting library with the declaration in the header like:
extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...)
PRINTFLIKE(4,5);
The PRINTFLIKE is in upper-case so that I can define it as nothing when I'm not using GCC. This use says that the first three arguments are nothing special, but the fourth argument is a format string like the ones used by printf() (indeed, internally, it gets passed to vfprintf()), and the arguments corresponding to it (formatted using the format string) start with the fifth argument.
This means that if I type:
err_logmsg(stdout, ERR_ABORT, 1, "%s: %d\n", errno, strerror(errno));
I will get a compilation error because errno is an int and strerror(errno) returns a pointer to a string. I can fix the error by changing the format string or the fifth and sixth arguments. (ERR_ABORT is a set of flags defined in the same header that declares err_logmsg().)
There are two numbers in the PRINTFLIKE macro because there could be other arguments between the format string and the first of the arguments used by the format string. For example, an alternative function could be:
extern void err_writer(FILE *fp, const char *format, int flags, int estat, ...)
PRINTFLIKE(2,5);
This tells the compiler that the format string is the second argument, but that the corresponding arguments that get formatted still appear starting at the fifth argument.
The header file for this code contains the lines:
#ifdef __GNUC__
#define PRINTFLIKE(n,m) __attribute__((format(printf,n,m)))
#define NORETURN() __attribute__((noreturn))
#else
#define PRINTFLIKE(n,m) /* If only */
#define NORETURN() /* If only */
#endif /* __GNUC__ */
Probably tells the compiler that the corresponding function has printf-like semantics.
This can enable the compiler to issue warnings at compile-time when the modifiers in the format string do not correspond to the type or the count of the passed arguments.
There is no other way that the compiler can have the knowledge to tell you that %u isn't the right formatting for an int when calling printf, sprintf, fprintf, etc.
I asked the reverse question a few months ago: Are printf/sprintf compiler warnings a conceptual break?

Can I substitute __func__ into an identifier name in a C macro?

I'd like to write a C macro which takes this:
int foo() {
MY_MACRO
}
and expands it to this:
int foo() {
_macro_var_foo++;
}
I've found that I can't use __func__, because that doesn't actually get expanded in the macro; it's treated by the preprocessor like a variable.
Is there some way to get this to work?
The preprocessor doesn't know about functions, just source files and line numbers. At that stage it's not performing syntactical analysis, just textual analysis and substitutions. That's why __func__ is a magical variable instead of a magical macro like __FILE__ and __LINE__.
In the C99 standard, __func__ is given a special new category of 'predefined identifier' (in section 6.4.2.2 Predefined Identifiers):
The identifier __func__ shall be implicitly declared by the translator as if,
immediately following the opening brace of each function definition, the declaration
static const char __func__[] = "function-name";
appeared, where function-name is the name of the lexically-enclosing function
This means that it is out of the scope of the C preprocessor, which is not aware of function boundaries or function names. Further, it would expand to a string, which makes it inappropriate for embedding into a variable name.
The GCC (4.4.1) manual says in section 5.43 (Function Names as Strings):
These identifiers [meaning __func__, __FUNCTION__ and __PRETTY_FUNCTION__] are not preprocessor macros. In GCC 3.3 and earlier, in C only, __FUNCTION__ and __PRETTY_FUNCTION__ were treated as string literals; they could be used
to initialize char arrays, and they could be concatenated with other string literals. GCC
3.4 and later treat them as variables, like __func__. In C++, __FUNCTION__ and __PRETTY_FUNCTION__ have always been variables.
If there was a way to get the function name into a preprocessor cleanly, then it is probable that the documentation here would have cross-referenced it, if it did not define it.
Technically, the answer to your question is "yes", there is "some way". But I think you already knew that, and it's true that you cannot deal with this at the macro preprocessor level.
Sure, there is always a way, you just might need a really long tape on that Turing Machine.
I think you already know this, but for the record you can get the overall result you want with:
#define MY_MACRO f_dictionary(__func__, ADDONE);
So now, you just need to implement f_dictionary and an ADDONE op for it.
You can do this using token concatenation.
#define MY_MACRO(baz) _macro_var_##baz++;
#define FUNC_WRAPPER(bar)\
int bar()\
{\
MY_MACRO(bar)\
}
FUNC_WRAPPER(foo)
The output from gcc -E:
int foo(){ _macro_var_foo++;}
Version dealing with argument lists using variadic macros and x macros:
#define MY_MACRO(baz) _macro_var_##baz++;
#define FUNC_DEF(ret_type,bar,...)\
ret_type bar(__VA_ARGS__)\
{\
MY_MACRO(bar)\
FUNC_CONTENTS\
}
#define FUNC_CONTENTS\
printf("Do some stuff\n", s1, s2);
FUNC_DEF(int, foo, char *s1, char *s2)
#undef FUNC_CONTENT

Resources