Related
I see this link Passing variable arguments to another function that accepts a variable argument list. What is the syntax to pass it to a macro as well?
#include <stdarg.h>
#define exampleW(int b, args...) function2(b, va_args)
static void exampleV(int b, va_list args);
void exampleB(int b, ...)
{
va_list args;
va_start(args, b);
exampleV(b, args);
//also pass args to a macro which takes multiple args after this step
??? [Is it exampleW(b, ##args)]
va_end(args);
}
static void exampleV(int b, va_list args)
{
...whatever you planned to have exampleB do...
...except it calls neither va_start nor va_end...
}
This is not possible. Macros are expanded at compile time, and so their arguments need to be known at compile time, at the point where the macro is used. The arguments to your function exampleB are in general not known until run time. And even though in many cases the arguments may be known when the call to the function is compiled, that may be in a different source file, which does not help you with macros in this source file.
You'll need to either:
have exampleB instead call a function like vfunction2 which is function2 rewritten to take a va_list parameter
reimplement exampleB as a macro
if there are a finite number of possible combinations of arguments to exampleB, then write code to handle all the cases separately:
if (b == TWO_INTS) {
int i1 = va_arg(args, int);
int i2 = va_arg(args, int);
exampleW(i1, i2);
} else if (b == STRING_AND_DOUBLE) {
char *s = va_arg(args, char *);
double d = va_arg(args, double);
exampleW(s,d);
} else // ...
do something non-portable to call the function function2 with the same arguments as were passed to exampleB, e.g. with assembly language tricks, or gcc's __builtin_apply().
I am confused by the following function definition without a compound statement in C:
void
__tu_finishme(const char *file, int line, const char *format, ...)
tu_printflike(3, 4);
It seems to not result in a function in generated object files, while the linker still expects __tu_finishme to have been written.
Especially odd to me since
void
__tu_finishme(const char *file, int line, const char *format, ...) {
tu_printflike(3, 4);
}
seems to have different (AKA "normal") linkage than the former.
Can someone please explain which concept and niche of the C language I encounter here and how it works?
Bonus points for explaining things like:
void
foo(const char* c)
bar()
{
ha = hoo();
boo(ha);
}
tu_printflike is very likely a macro that expands to an attribute like:
__attribute__ ((format (printf, 3, 4)))
The above is GCC specific, so the use of a macro is there to enable portability across compilers, it can be defined as something akin to
#ifdef __GNUC__
# define tu_printflike(i, j) __attribute__ ((format (printf, i, j)))
#else
# define tu_printflike(i, j)
#endif
Your bonus point can be explained just the same with
#define bar()
Where the definition is just an empty token sequence, the function like macro expands to nothing.
Is it possible to expand a macro which accepts multiple arguments to a different macro if first argument is not the expected value
E.g
int main()
{
PRINT(2, "%d%d\n", i, j); //should expand to syslog(2, "%d%d\n", i, j)
PRINT("%d%d\n", i, j); //arg1 which is expected to be an int is not preset.
/* This should expand differently may be to a default level say 3. syslog(3, "%d%d\n", i,j); */
}
I would have tried this kind of over loading if I knew total number of args.
I really recommend to write two separate macros for this, just as you would write two differently named functions for the two signatues in C. (I would rather write macros that tell you what level they are explicitly, like ERROR(...), WARNING(..) etc. than introduce a default argument.)
That said, there are two possibilities to achieve what you want.
C11 _Generic selections
The _Generic keyword was introduced with C11. It allows to expand macros in a switch-like manner according to the type of an argument; Robert Gamble has a good introduction.
You want to distinguish two cases: First argument is a string and first argument is an integer. A drawback is that in _Generic, a string literal isn't treated as char * or const char *, but as char[size]. For example, "%d" is a char[3].
In your case, we can get around this by treating a string as anything that isn't an integer. The compiler will sort out all non-string, non-integer arguments later. So:
#define PRINT(fmt, ...) \
_Generic(fmt, \
int: syslog(fmt, __VA_ARGS__), \
default: syslog(3, fmt, __VA_ARGS__))
There are drawbacks: You can't have a single-argument call, because that would leave a comma in the call. (gcc's ##__VA_ARGS__ gets around that.) And the _Generic keyword is not yet widely implemented; this solution will make your code highly unportable.
String introspection hack
Ordinary C99 macros have no information on their type. C code can make a guess, however. Here's an example that checks whether a macro argument is a string literal:
#define PRINT(sev, ...) \
if (#sev[0] == '"') syslog(3, sev, __VA_ARGS); \
else syslog(sev, __VA_ARGS__);
This works -- almost. The compiler will probably compile the constant condition away and only gererate code for one of the branches. But it will parse the branches anyway and the dead branch will have a wrong function signature, which will generate warnings.
You can get around this by writing a variadic front-end function in C. Here's an example that works:
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#define HEAD(X, ...) X
#define STR_(x) #x
#define STR(x) STR_(x)
#define PRINT(...) \
msg(*STR(HEAD(__VA_ARGS__)) == '"', __VA_ARGS__)
int msg(int dflt, ...)
{
va_list va;
int sev = 3;
const char *fmt;
va_start(va, dflt);
if (!dflt) sev = va_arg(va, int);
fmt = va_arg(va, const char *);
fprintf(stderr, "[%d] ", sev);
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
return 0;
}
int main()
{
PRINT(1, "Incompatible types %s and %s", "Apple", "Orange");
PRINT("Microphone test: %d, %d, %d, ...", 1, 2, 3);
return 0;
}
This solution is dangerous, because the msg function is only safe if it is generated by the macro. And the macro is only safe if the format string is a string literal beginning with a double quote. The macro expands the arguments by one boolean argument to the left and hides the argument incompatibility in a variadic argument list.
It may be a nice trick, but you'll be better off having separate, clearly named macros.
C macros do not have the ability to inspect their arguments. As noted in the answer you posted, there is a sneaky way to do different things based on the number of arguments, but that's the extent of it. If you already have a variable number of arguments outside of the overload you are trying to do, it will not be possible. If all you need is a default level:
#define PRINTNORM(...) PRINT(3, __VA_ARGS__)
or whatever you'd like to call it. IMHO, cleaner code than overloading PRINT.
Simply use another value for your need. And perhaps a bit of magic with variadic macro would help.
something like:
#define PRINT( print_level , print_string , ... )\
switch( print_level ) \
/* as many syslog cas as needed */
case( 5 ):\
case( 4 ):\
case( 3 ):\
case( 2 ):\
case( 2 ):\
case( 1 ):\
syslog( print_level , __VA_ARGS__ );\
break ; \
default: \
case( 0 ): \
printf( __VA_ARGS__ ); \ /* else we simply want to print it */
break ;
Edit:
Doc on variadic macro: https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
P99 has conditional macro evaluation. Here you could probably use something like P99_IF_EMPTY for something like
#define PRINT(LEV, ...) my_print(P99_IF_EMPTY(LEV)(3)(LEV), __VA_ARGS__)
this would still have you insert a , for the case of the empty argument but comes probably close to what you want to achieve.
Optional arguments coming before other mandatory arguments can potentially be handled by folding them together in parentheses:
PRINT((2, "%d%d\n"), i, j);
PRINT("%d%d\n", i, j);
Define PRINT like this:
#define PRINT(SL, ...) PRINT_LEVEL(APPLY(CAT(LEVEL, IS_SPLIT(SL)), IDENTITY SL), APPLY(CAT(FSTRING, IS_SPLIT(SL)), IDENTITY SL), __VA_ARGS__)
#define PRINT_LEVEL(LEVEL, ...) syslog(LEVEL, __VA_ARGS__)
PRINT detects whether the first argument is an atom (just the format string) or a parenthesized list of two elements (printlevel + string), and expands into the real implementation PRINT_LEVEL accordingly, either extracting the level from the first argument, or supplying a default value.
Definitions for IS_SPLIT and the other helpers are as follows:
#define LEVEL_0(_S) 3
#define LEVEL_1(L, S) L
#define FSTRING_0(S) K_##S
#define FSTRING_1(L, S) S
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A ## B
#define APPLY(F, ...) F(__VA_ARGS__)
#define IDENTITY(...) __VA_ARGS__
#define K_IDENTITY
#define IS_SPLIT(...) IS_SPLIT_1(IDENTITY __VA_ARGS__)
#define IS_SPLIT_1(...) IS_SPLIT_2(__VA_ARGS__, _1, _0, _)
#define IS_SPLIT_2(_X, _Y, R, ...) R
GCC gives me the following:
warning: passing argument 2 of ‘_panic’ discards qualifiers from pointer target type
misc.h:191: note: expected ‘char *’ but argument is of type ‘const char *’
The second argument is of type md_addr_t. How can I cast this to char* and what does md_addr_t meant to be? (Neither man-page could help me nor google)
The reason has been pointed out by larsmans correctly. This warning is seen when casting const away i.e. if a function take non-const argument but you pass const argument, then if the function modifies the argument passed you have undefined behaviour. md_addr_t which is typedef in the code has nothing to do with this. In the code you are getting these warning on using panic which is defined as follows (source from ss-ppc-little.tgz in your link):
#ifdef __GNUC__
/* declare a panic situation, dumps core */
#define panic(fmt, args...) \
_panic(__FILE__, __FUNCTION__, __LINE__, fmt, ## args)
void
_panic(char *file, char *func, int line, char *fmt, ...)
__attribute__ ((noreturn));
#else /* !__GNUC__ */
void
panic(char *fmt, ...);
#endif /* !__GNUC__ */
On Unix/Linux system __GNUC__ is defined thus the first definition is used in which you are pre pending file name (__FILE__), function name (__FUNCTION__) & line number (__LINE__) before printing out the message. (See this link for details).Here as you can see _panic expects char* as first & second arguments but arguments being passed are __FILE__ & __FUNCTION__ where __FUNCTION__ is static const char[]. You can change _panic(char *file, char *func, int line, char *fmt, ...) to _panic(char *file, const char func[], int line, char *fmt, ...) or to _panic(char *file, const char *func, int line, char *fmt, ...) - as the compiler is complaining fix your warning. As__FILE__ is also constant you can consider changing to _panic(const char *file, const char *func, int line, char *fmt, ...)
Hope this helps!
grep -R md_addr_t /usr/include does not return anything in a well-populated /usr/include, nor does it ring a bell. It must be something in your application/library.
In any case, casting to char * is just a matter of prefixing (char *), which is also one of the few casts that are guaranteed to always work in C, although casting const away might mean that someone is going to write to read-only memory, which is not guaranteed to work...
I have zillions of my_printf() function calls in a huge program. I now want to convert them all so that the function takes a new integer argument (call it x) without having to edit the zillions of calls. If my_printf only ever took exactly one string argument then I could do something like this:
#define my_printf(str) _my_printf(x,str)
void _my_printf(int x,char *str) // changed from my_printf(char *str)
{
// stuff
}
But as my_printf takes a variable number of arguments I'm not sure how to do it. Can it be done?
EDIT: for those wondering why I should want to do such a thing, here's a related example:
#if BELT_AND_BRACES_DIAGNOSTIC_MODE
#define function(x) _function(__FILE__,__LINE__,x)
#else // speed critical optimised mode
#define function(x) _function(x)
#endif
#if BELT_AND_BRACES_DIAGNOSTIC_MODE
void _function(char *file,int line,int x)
#else
void _function(int x)
#endif
{
// stuff
#if BELT_AND_BRACES_DIAGNOSTIC_MODE
if (something_went_wrong)
{
printf("Cock up in function when called from %s line %d\n",file,line);
}
#endif
}
You may use C99 variadic macros:
#define my_printf(...) my_printf_(x, __VA_ARGS__)
As Microsoft's implementation suppresse trailing commas, the str argument can be added explicitly
#define my_printf(str, ...) my_printf_(x, str, __VA_ARGS__)
but this would lead to a syntax error in standard C when invoked without variadic arguments
my_printf("foo")
or an empty argument list
my_printf("foo",)
Therefore, I'd go with the first version.
If the code can be compiled as C99 code, you can define a variadic macro
#define my_printf(str, args...) _my_printf(x, str, ##__VA_ARGS__)
The preprocessor will replace the arguments ... and the GNU preprocessor will remove the trailing comma in case the macro is invoked only with the str argument.
The best thing is of course to bite the bullet and edit the code. Otherwise you're creating a "mystery", that needs to be solved by all future maintainers of the code. Even if that's only you, this is exactly the kind of clever trick that you will forget all about. It sucks to come back, and be puzzled by strange pointless-seeming macros.
That said, if you're using a GNU toolchain, you can perhaps look into using varargs macros.
Not with standard C89 macros, you can't. However you can get the same effect using functions, by breaking out the main part of your my_printf function into a vmy_printf function, analagous to the standard vprintf:
#include <stdarg.h>
int vmy_printf(int x, const char *format, va_list ap)
{
/* main body of my_printf goes here, taking its varargs from ap */
}
/* new_my_printf(), for callers who know about the x parameter */
int new_my_printf(int x, const char *format, ...)
{
int n;
va_list ap;
va_start(ap, format);
n = vmy_printf(x, format, ap);
va_end(ap);
return n;
}
/* my_printf(), for the old callers who don't know about x */
int my_printf(const char *format, ...)
{
int n;
va_list ap;
va_start(ap, format);
n = vmy_printf(DEFAULT_X, format, ap);
va_end(ap);
return n;
}
(This kind of thing is why those v... versions of all the standard varargs functions exist.)
If my_printf already takes a variable number of arguments, I'm not sure why you need to wrap 'one more argument' in a macro... Just insert the new calls with the extra argument and be done with it; the old calls should still work as expected.
A simple solution to this problem is...
#define my_printf(x) printf x
(note the missing braces)
To call it, use:
my_printf((any number of arguments))
(note the double braces)