Related
okay this sounds weird, the title is kinda
confusing but heres what i mean basically :
#define make_name(id) cool_name_##id
#define my_cool_macro(id, type) void fun_##make_name(id)(type arg1)
my_cool_macro(hello, char);
this should expand to
/*
* passed through my_cool_macro
* vvvvv
*/
void fun_cool_name_hello(char arg1);
/* ~~~~^^^^^^^^^^^^^^^ */
~ -- my_cool_macro
^ -- make_name
i dont have a better way to explain this,
any way to make this work ?
basically :
define a function-like macro which can generate names
define another function-like macro which calls to the defined name creating macro with an argument passed to the function creator macro
why am i doing this
im kinda trying to implement templaces in c using macros and as you know templated functions can have different types and i want to mangle the names but not repeat the cool_name_... because what if i want to change the cool_name to some_name
the solution should also work similarly to my example, so fun_##make_name(hello) should work as should hello_##make_name(hello) and ewuihewuifh_##make_name(hello) without me needing to define a macro for every change
You can do:
#include <stdio.h>
#define join(x, y) x##y
#define make_name_l(fn, id, arg_type) fn##id(arg_type)
#define make_name(fn, id, arg_type) make_name_l(fn, id, arg_type)
#define my_cool_macro(ret_type, id, arg_type) ret_type make_name(join (fun_, cool_name_), id, arg_type)
my_cool_macro(void, hello, char);
int main (void) {
fun_cool_name_hello('a');
return 0;
}
void fun_cool_name_hello (char a) {
printf ("In function : %s, arg : %c\n", __func__, a);
}
Additional:
In case, if you want to make it work with any type or number of arguments then you can use ellipsis (...) and __VA_ARGS__.
include <stdio.h>
#define join(x, y) x##y
#define make_name_l(fn, id, ...) fn##id(__VA_ARGS__)
#define make_name(fn, id, ...) make_name_l(fn, id, __VA_ARGS__)
#define my_cool_macro(ret_type, id, ...) ret_type make_name(join (fun_, cool_name_), id, __VA_ARGS__)
my_cool_macro(void, hello, char);
my_cool_macro(int, multiple_args, char, int, const char *);
my_cool_macro(void, no_args, void);
int main (void) {
const char * str = "test";
fun_cool_name_hello('a');
fun_cool_name_multiple_args('x', 5, str);
fun_cool_name_no_args();
return 0;
}
void fun_cool_name_hello (char a) {
printf ("In function : %s, arg : %c\n", __func__, a);
}
int fun_cool_name_multiple_args (char c, int i, const char * pstr) {
printf ("In function : %s, c : %c, i : %d, str : %s\n", __func__, c, i, pstr);
return i;
}
void fun_cool_name_no_args (void) {
printf ("In function : %s\n", __func__);
}
Output:
# ./a.out
In function : fun_cool_name_hello, arg : a
In function : fun_cool_name_multiple_args, c : x, i : 5, str : test
In function : fun_cool_name_no_args
https://godbolt.org/z/d67MWjasz
You could have a macro that creates the prototype along with its type, as well as one that makes your custom name.
#define name(f) cool_name_##f
#define make_function(type, name, arg) type fun_name(arg)
#include <stdio.h>
#define name(f) cool_name_##f
#define make_function(type, name, arg) type fun_name(arg)
make_function(void, name(hello), int);
void cool_name_fun_hello(int f) {
printf("%d\n", f);
}
int main(void) {
cool_name_fun_hello(1);
}
I have the following code where I format a message that has been passed via a logger:
va_list args;
va_start(args, level);
// pop the msg and do some string replaces
char *msg = va_arg(args, char*);
ssize_t len = str_replace(tmp, "%(msg)s", msg, output, 1024);
// now how to get it 'back in' so I can print it?'
// msg = output
vfprintf(stderr, output, args);
The above code prints nothing, as it seems to have 'popped' the msg without me placing the updated msg back in there. What would be a possible way to do this?
Instead of fiddling with the format string, you could print the variadic arguments passed to the log function to a string first, then print that string with a regular fprintf via the %s format.
You haven't posted your function signature, but it looks as if you passed the format string as first variadic argument. That's unusual. I've changed the signature so that the format string is the last non-variadic arg. That's common and it also opens up the possibility to chech your format strings for correctness. (See below.)
Here's an example implementation:
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
enum {
FATAL, ERROR, WARNING, INFO, NLEVEL
};
void say(int level, const char *fmt, ...)
{
static const char *templates[NLEVEL] = {
"\033[1m!!! FATAL: %s !!!\033[0m\n",
"ERROR: %s\n",
"Warning: %s\n",
"%s Just sayin'.\n"
};
const char *tmp;
char output[1024];
va_list args;
// print arguments to temporary string
va_start(args, fmt);
vsnprintf(output, sizeof(output), fmt, args);
va_end(args);
// find and print template string with message
if (level < 0) level = 0;
if (level >= NLEVEL) level = INFO;
tmp = templates[level];
fprintf(stderr, tmp, output);
va_end(args);
if (level == FATAL) exit(1);
}
Use it like this:
int main(int argc, char *argv[])
{
int a = 6;
int b = 7;
double Tmin = -273.15;
say(INFO, "%d * %d == %d.", a, b, a * b);
say(INFO, "The %s is %s.", "apple", "red and juicy");
say(WARNING, "Temperature falls below Tmin (%gC)", Tmin);
say(ERROR, "That should %s have happened.",
(rand() % 2) ? "never" : "not really");
say(FATAL, "Out of coffee!");
return 0;
}
Finally, you can make your logging functions safer and let the compiler check the validity of format strings. GCC and Clang do this with arguments, the Microsoft compiler does it with SAL, the Source-code Annotation Language. Other compilers may have their own method to do such checks. (More likely, they just emulate one of the GC or MS systems.)
With a little macro dance in the header you can cater for both variants:
#if defined(_MSC_VER)
#define PRINTF_FMT _Printf_format_string_
#endif
#if defined(__GNUC__) || defined(__clang__)
#define PRINTF_ARGS(IFMT, IARGS) __attribute__((format(printf, IFMT, IARGS)))
#endif
#ifndef PRINTF_ARGS
#define PRINTF_ARGS(IFMT, IARGS)
#endif
#ifndef PRINTF_FMT
#define PRINTF_FMT
#endif
void say(int level, PRINTF_FMT const char *fmt, ...) PRINTF_ARGS(2, 3);
Now a call like this:
say(WARNING, "Meta: Wrong formt for %d.", ~0ull);
warns you about the wrong format specifier.
I'm trying to pass mixed types to printf(). In the actual code (at the bottom) I also pass the format placeholder so that printf() knows how to format.
While accidently using these void* pointers directly as call by values, I discovered that my code was not working as expected.
So I created a test program, searched and poked around until I came up with this solution.
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void test1(void* a) {
printf("value: %d\n", *(int*)a);
}
void test2(void* a) {
printf("value: %f\n", *(float*)a);
}
int main(int argc, char** argv) {
int* aip = &(int){1};
test1(aip);
int ai = 1;
test1(&ai);
float af = 1.75;
test2(&af);
return 0;
}
But I don't want hardcoded *(int*) or *(float*) dereferencing and casting but actually write something like this:
void test(void* a) {
printf("value: %VARIES\n", a);
}
VARIES is passed into test() and concatenated into the final formatter string.
The actual function looks like this:
void fn(void* value, char* fmtChar) {
char fmtHelper[50];
// fill fmtChar in formatter string's %s placeholder
snprintf(fmtHelper, sizeof(fmtHelper), "value : %s\n", fmtChar);
// actually print value varying argument
printf(fmtHelper, value);
}
My curent workaround uses switch/case statements and determines the casting and formatter placeholders programmatically.
If you're targeting current C (C11), you can use a type-generic expression with a macro to make a type-generic function:
#include <stdio.h>
void print_int(int x) {
printf("an int: %d\n", x);
}
void print_double(double x) {
printf("a double: %f\n", x);
}
#define print(X) _Generic((X), \
float: print_double, \
double: print_double, \
default: print_int \
)(X)
int main(void) {
print(1); // an int: 1
print(1.0); // a double: 1.00000
}
This solution uses vprintf and va_list macros, so they're resolved during the preprocessing of the source.
#include <stdio.h>
#include <stdarg.h>
void print(char* msg, char* fmtChars, ...) {
// format string and write the result to fmtHelper
// %s is replaced with the value placeholder types
// (fixed length for simplicity)
char fmtHelper[50];
snprintf(fmtHelper, sizeof(fmtHelper), "%s; value 1: %s, value 2: %s\n", msg, fmtChars, fmtChars);
va_list args;
// treat all parameters _after_ this named as variable arg
va_start(args, fmtChars);
vprintf(fmtHelper, args);
va_end(args);
}
int main(void) {
char* msg = "Test";
int in1 = 1;
int in2 = 2;
float fl1 = 4.21;
float fl2 = 5.89;
print(msg, "%f", fl1, fl2);
print(msg, "%d", in1, in2);
}
This was a hint #rici gave in the comments section.
I have been trying to pass variable arguments to other function in C but it is producing inconsistent result in different runtime environment as well as in different runs in same environment:
int main()
{
int result = myprintf("Something \n %d", 9);
return result;
}
int myprintf(const char *format, ...){
printf("Something \n %d", 9);
printf("\n");
va_list args;
va_start(args, format);
int result = printf(format,args);
printf("\n");
va_end(args);
return result;
}
And the result produced is:
WWW.FIRMCODES.COM
9
WWW.FIRMCODES.COM
438656664
I could not find the reason for "438656664".
You cannot pass the variadic arguments to a variadic function. Instead, you must call a function that takes a va_list as argument. The standard library provides variants of printf and scanf that take a va_list; their names have the prefix v.
Your example should look like:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
int printfln(const char *format, ...)
{
int result;
va_list args;
va_start(args, format);
result = vprintf(format, args);
printf("\n");
va_end(args);
return result;
}
int main()
{
int result = printfln("Something \n %d", 9);
printf("(%d)\n", result);
return 0;
}
There are some gotchas, for example when you want to call two v... function for printing to the screen and a log file: The v... function may exhaust the va_list, so you must pass in a fresh one to each call if your code should be portable.
For the C++ fellow also reading this. You can actually do it using pack expansion without using vprintf.
This trick is quite handy when you need to wrap a method that takes the ellipsis (...)
and not a va_list.
For instance:
template <class ... Args>
void foo(const char *format, Args ... args)
{
printf(format, args...);
}
Here class ... Args is template parameter pack, Args ... args is function parameter pack, and args... is function parameter pack expansion.
Alternatively, you can simply use a wrapper macro:
#include <stdio.h>
#define myprintf(fmt, ...) ( printf("Something \n %d\n", 9), printf(fmt, __VA_ARGS__) )
int main (void)
{
int result = myprintf("Something \n %d\n", 9);
printf("%d\n", result);
}
Note the use of the comma operator to preserve the returned value of the right-hand printf call to the caller.
This isn't any less type safe than the (equally dangerous) stdarg.h variadic functions.
Just a simple demonstration and worked example with "a fresh one va_list" when you need to print/output-as-string a template string like constexpr const char* example = R"(template "%s")"; .
std::string print_templ(const char* format, ...)
{
va_list args1;
va_start(args1, format);
va_list args2;
va_copy(args2, args1);
std::vector<char> str(std::vsnprintf(nullptr, 0, format, args1) + 1);
va_end(args1);
const int ret = std::vsnprintf(str.data(), str.size(), format, args2);
va_end(args2);
return std::string(str.begin(), str.begin()+ret);
}
I want to write a variadic macro that somehow knows the names of the arguments passed.
For example:
The code:
int x = 2;
float f = 4.6;
char c = 'A';
char* str = "Bla bla";
PRINT("%d %f %c %s", x, f, c, str); // calling the macro
shall produce the output
x=2 f=4.6 c=A str=Bla bla.
Hope someone knows the answer to that.
Close but not exactly (only works for single expression) what the asker required:
#define PRINT(fmt, var) printf(#var " = " fmt, (var))
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#define PRINT(fmt, var) printf(#var " = " fmt, (var))
int
main(int argc, char *argv[])
{
int x = 2, y = 3;
float f = 4.6;
char c = 'A';
char *str = "Bla bla";
PRINT("%d\n", x);
PRINT("%f\n", f);
PRINT("%c\n", c);
PRINT("%s\n", str);
PRINT("%d\n", x+y);
exit(EXIT_SUCCESS);
}
I don't think you can achieve what you want.
But something like this might be yours:
#define PRINT(fmt, val) fprintf(stderr, "%s=" fmt, #val, val)
...
int x = 2;
float f = 4.6;
char c = 'A';
char* str = "Bla bla";
// calling the macro:
PRINT("%d ", x);
PRINT("%f ", f);
PRINT("%c ", c);
PRINT("%s\n", str);
Read carefully the documentation of cpp. In particular, about macro arguments, stringification, concatenation, and variadic macros. It is well explained there.
You probably might not be able to achieve exactly what you want, because you need to split the format string.
Perhaps lower your goals (e.g. accept only one argument for PRINT, see this or that answers) or consider using a more powerful preprocessor like GPP.
You could also perhaps customize GCC (by adding your builtins) with e.g. MELT but that is probably not worth the weeks of efforts (for a newbie) required to do so.
Slightly what you may want:
#include <stdio.h>
#define STRINGIFY(x) #x, (x)
#define FPRINTF(file, fmt, ...) fprintf(file, fmt, __VA_ARGS__)
#define PRINTF(fmt, ...) FPRINTF(stdout, fmt, __VA_ARGS__)
int main(void)
{
int i = 42;
char ch = 'a';
char str[4] = "alk";
PRINTF("%s=%s, %s=%c, %s=%d\n",
STRINGIFY(str),
STRINGIFY(ch),
STRINGIFY(i)
);
/* of just use printf directly: */
printf("%s=%s, %s=%c, %s=%d\n",
STRINGIFY(str),
STRINGIFY(ch),
STRINGIFY(i)
);
return 0;
}
/Puts on Indiana Jones` hat/
I may be a tad too late, but I`m here to say that this problem does have a proper(-ish) solution.
First, some prerequisite defines (explanation here):
#define L(c, ...) \
L4(c,1,0,,,,,,,,,,,,,##__VA_ARGS__) L4(c,0,1,,,,,,,,,##__VA_ARGS__) \
L4(c,0,2,,,,, ##__VA_ARGS__) L4(c,0,3, ##__VA_ARGS__)
#define L4(c, f, n, ...) \
L3(c,f,n##0,,,,__VA_ARGS__) L3(c,0,n##1,,,__VA_ARGS__) \
L3(c,0,n##2,, __VA_ARGS__) L3(c,0,n##3, __VA_ARGS__)
#define L3(...) L2(__VA_ARGS__, \
1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, )
#define L2(c, f, \
n00,n01,n02,n03, n04,n05,n06,n07, n08,n09,n0A,n0B, n0C,n0D,n0E,n0F, \
a00,a01,a02,a03, a04,a05,a06,a07, a08,a09,a0A,a0B, a0C,a0D,a0E,a0F, \
s, ...) L##s(c, f, n00, a00)
#define L1(c, f, n, a) c##f(n, a)
#define L0(c, f, n, a)
Then the code, which is actually an extension of #alk`s answer:
#include <stdio.h>
#define STRING1(n, a) #a, (a)
#define STRING0(n, a) , STRING1(n, a)
#define PRINTF(fmt, ...) printf(fmt, L(STRING, __VA_ARGS__))
int main(int argc, char *argv[]) {
int i = 42;
char ch = 'a';
char str[4] = "alk";
/** every var must be preceded with '%s' for its name to be shown **/
PRINTF("%s=%s, %s=%c, %s=%d\n", str, ch, i);
return 0;
}
This version is only suited for [0..16] arguments, but it can be easily extended to any argument count, especially to powers of 2. However, the more arguments it supports, the less elegant it looks.
P.S.: #BasileStarynkevitch has already provided all the right links to clarify how this works.
The next works for me in gcc 4.7 :
#include <stdio.h>
#define PRINT(...) fprintf (stderr, __VA_ARGS__)
int main()
{
int x = 2;
float f = 4.6;
char c = 'A';
char* str = "Bla bla";
PRINT("%d %f %c %s", x, f, c, str); // calling the macro
}
(please note that i have edited the macro invocation changing a %s for a %c)
Regards