I have a printf statement as follows:
printf("[%d] %d", i, n->data);
I'm trying to make the related code flexible so you can change the variable type of "n->data" depending on your need. Is there a way to make the format specifier update depending on the variable type used?
I've tried including:
const char FS[2] = "%f";
when the variable is a float, then amending the printf statement to:
printf("[%d] "FS, i, n->data);
but this gets the following error, which I don't know how to resolve:
dLList.c:125:23: error: expected ')'
printf("[%d] "FS, i, n->data);
^
dLList.c:125:15: note: to match this '('
printf("[%d] "FS, i, n->data);
^
1 error generated.
Any ideas?
Thanks
Instead of const char FS[2] = "%f";, you may try to use macro like this:
#define FS "%f"
that would aggregate the control string format as you apparently want.
Is there a way to make the format specifier update depending on the variable type used?
Yes, C11 has _Generic. This allows code selection based on the type of the expression. The selection is not evaluated at run-time, but at compile time, the type is determined.
#include <stdio.h>
#include <stdlib.h>
#define print(X) printf(_Generic((X), \
double: "%e\n", \
int: "%i\n", \
char *: "%s\n", \
default: "TBD" \
) , X)
int main(void) {
print(5.0);
print(5);
print("Five");
print(1.0f);
return 0;
}
Output
5.000000e+00
5
Five
TBD
You could use an enum and a lookup table for format strings.
Just make sure your struct that contains the data also contains a matching enum describing the type of data currently contained in the struct.
That way you can write a print function that accepts such a struct as an argument and prints its value using a correct format string for that type of data.
#include <stdio.h>
typedef enum Format_
{
/* Add/remove formats as needed. */
SIGNED_DECIMAL_INT,
UNSIGNED_DECIMAL_INT,
DECIMAL_FLOATING_POINT,
STRING,
POINTER_ADDRESS,
NUM_SUPPORTED_FORMATS
} Format;
static const char* formatStrings[NUM_SUPPORTED_FORMATS] =
{
"%d\n", /* Add more complex format strings if needed. */
"%u\n",
"%f\n",
"%s\n",
"%p\n"
};
typedef struct Wrapper_
{
Format format;
float data;
} Wrapper;
void printData(const Wrapper *const wrapper)
{
printf(formatStrings[wrapper->format], wrapper->data);
}
int main(void)
{
Wrapper wrapper;
wrapper.format = DECIMAL_FLOATING_POINT;
wrapper.data = 12.345f;
/* Prints 12.345000 */
printData(&wrapper);
return 0;
}
Related
This questions is about my homework.
This topic is need to use like:
#define GENERIC_MAX(type)\
type type##_max(type x, type y)\
{\
return x > y ? x : y;\
}
The content of the question is to make this code run normally:
#include <stdio.h>
GenerateShowValueFunc(double)
GenerateShowValueFunc(int)
int main()
{
double i = 5.2;
int j = 3;
showValue_double(i);
showValue_int(j);
}
The result of the operation is like this:
i=5.2000
j=3
And this code is my current progress, but there are have problems:
#include <stdio.h>
#define printname(n) printf(#n);
#define GenerateShowValueFunc(type)\
type showValue_##type(type x)\
{\
printname(x);\
printf("=%d\n", x);\
return 0;\
}
GenerateShowValueFunc(double)
GenerateShowValueFunc(int)
int main()
{
double i = 5.2;
int j = 3;
showValue_double(i);
showValue_int(j);
}
I don’t know how to make the output change with the type, and I don’t know how to display the name of the variable. OAO
This original task description:
Please refer to ShowValue.c below:
#include <stdio.h>
GenerateShowValueFunc(double)
GenerateShowValueFunc(int)
int main()
{
double i = 5.2;
int j = 3;
showValue_double(i);
showValue_int(j);
}
Through [GenerateShowValueFunc(double)] and [GenerateShowValueFunc(int)] these two lines macro call, can help us to generated as [showValue_double( double )] and [showValue_int( int )] function, And in main() function called. The execution result of this program is as follows:
i=5.2000
j=3
Please insert the code that defines GenerateShowValueFunc macro into the appropriate place in the ShowValue.c program, so that this program can compile and run smoothly.
A quick & dirty solution would be:
type showValue_##type(type x)\
{\
const char* double_fmt = "=%f\n";\
const char* int_fmt = "=%d\n";\
printname(x);\
printf(type##_fmt, x);\
return 0;\
}
The compiler will optimize out the variable that isn't used, so it won't affect performance. But it might yield warnings "variable not used". You can add null statements like (void)double_fmt; to silence it.
Anyway, this is all very brittle and bug-prone, it was never recommended practice to write macros like these. And it is not how you do generic programming in modern C. You can teach your teacher how, by showing them the following example:
#include <stdio.h>
void double_show (double d)
{
printf("%f\n", d);
}
void int_show (int i)
{
printf("%d\n", i);
}
#define show(x) _Generic((x),\
double: double_show, \
int: int_show) (x) // the x here is the parameter passed to the function
int main()
{
double i = 5.2;
int j = 3;
show(i);
show(j);
}
This uses the modern C11/C17 standard _Generic keyword, which can check for types at compile-time. The macro picks the appropriate function to call and it is type safe. The caller doesn't need to worry which "show" function to call nor that they pass the correct type.
Without changing the shown C-code (i.e. only doing macros), which I consider a requirement, the following code has the required output:
#include <stdio.h>
#define showValue_double(input) \
showValueFunc_double(#input"=%.4f\n" , input)
#define showValue_int(input) \
showValueFunc_int(#input"=%d\n" , input)
#define GenerateShowValueFunc(type) \
void showValueFunc_##type(const char format[], type input)\
{\
printf(format, input); \
}
/* ... macro magic above; */
/* unchangeable code below ... */
GenerateShowValueFunc(double)
GenerateShowValueFunc(int)
int main()
{
double i = 5.2;
int j = 3;
showValue_double(i);
showValue_int(j);
}
Output:
i=5.2000
j=3
Note that I created something of a lookup-table for type-specific format specifiers. I.e. for each type to be supported you need to add a macro #define showValue_ .... This is also needed to get the name of the variable into the output.
This uses the fact that two "strings" are concatenated by C compilers, i.e. "A""B" is the same as "AB". Where "A" is the result of #input.
The rest, i.e. the required function definition is very similar to the teacher-provided example, using the ## operator.
Note, this is if the variable name has to correctly be mentioned in the output.
With out the i = things would be easier and would more elegantly use the generated functions WITHOUT having the called showValue_double(i); be explicit macros. I.e. the functions generated are 1:1 what is called from main(). I think that might be what is really asked. Let me know if you want that version.
I'm trying to assign data type to world but unable to figure it out.
#include <stdarg.h>
#include <stdio.h>
#define TRACE(arg) TraceDebug arg ;\
void TraceDebug(const char* format, ...);
void TraceDebug(const char* format, ...)
{
char buffer[256];
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
int main(void)
{
int a =55;
TRACE((Hello,a));
return 0;
}
Below is the error statement in detail.
main.c: In function 'main':
main.c:28:12: error: 'Hello' undeclared (first use in this function)
TRACE((Hello,a));
^
main.c:13:32: note: in definition of macro 'TRACE'
#define TRACE(arg) TraceDebug arg ;\
^
main.c:28:12: note: each undeclared identifier is reported only once for each function it appears in
TRACE((Hello,a));
^
main.c:13:32: note: in definition of macro 'TRACE'
#define TRACE(arg) TraceDebug arg ;\
^
Is there anyway possible to declare Hello as a variable, after declaring I need to get the address of the variable.
In simple I want to change the below code into a variadic function arguments
for example #define QU(arg1,arg2) as #define QU(arg1,...) since variadic macro is not supported am using variadic functions.
#define TRACE(arg1) QU arg1
#define QU(arg1,arg2) {static const char arg1; \
printf("%p\n",(void*)&arg1);\
printf("%d\n",arg2);}\
int main(void)
{
int aaa =333;
int bbb =444;
TRACE((Hello,aaa));
TRACE((Hello2,bbb));
return 0;
}
1) (title) How to declare the data type for variable arguments?
2) (1st question) I'm trying to assign data type to world but unable to figure it out.
1) The data type for the variadic argument (represented by the ellipses: ... ) is always the type of the variable preceding the ellipses . For this prototype:
int variadicFunc(int a, const char *b, ...);
^^^^^^^^^^ ^^^
type assumes the type const char *
2) From content of your question only, the answer could be to be use a typedef statement:
typedef char World; // a new type 'World' is created
But there are clarifications in the comments:
if i change the string to variable i can reduce the memory size,... (you)
You want to have a variable argument list to pass variables existing in your program that you want to place on a Trace list for debugging
purposes. (is that close?)... (me)
(is that close?) yes, that's the thing am trying to do... Are you always going to pass the same type to this function? Ahh, type will
be like TRACE(("Hello", a,"world")); (you)
It appears you want to enter a variable number of either string literals, or string variables as function arguments, then for those items to be placed into variables, then the addresses of those variables to be stored in a file, for the purpose of saving space.
The following code illustrates how you can pass a variable number of strings (in different forms) into a function, and have the address and content retained into a struct. From this, you should be able to adapt from what I have done here, to something more useful to your needs. Note, I have reserved the first string argument to be used a file location to store addresses.
#define MAX_LEN 200
typedef struct {
unsigned int addr;
char str[MAX_LEN];
} DATA;
int variadicFunc(int argCount, const char *str, ...);
int main(void)
{
char a[] = {"this is a string"};
char b[] = {"another string"};
char c[] = {"yet another string"};
// count non-variable v1 v2 v3 v4
variadicFunc(4, ".\\storage.txt", a, b, "var string", c);
// ^count of variable argument list
return 0;
}
int variadicFunc(int argCount, const char *str, ...)
{
va_list arg;
int i;
char sAddr[10];
DATA *d = calloc(argCount, sizeof(*d));
va_start(arg, str);
FILE *fp = fopen(str, "w");//using first string as filename to populate
if(fp)
{
for(i=0;i<argCount;i++)
{
// retain addresses and content for each string
strcpy(d[i].str, va_arg(arg, const char *));
d[i].addr = (unsigned int)&d[i].str[i];
sprintf(sAddr, "%X\n", d[i].addr);
fputs(sAddr, fp);
}
fclose(fp);
}
return 0;
}
Is there a way to convert gcc's typeof extension to a string, for example:
#define printType(a) printf("%s", #typeof(a))
So that I can do:
int a = 4;
printf("Type of a is: ");
printType(a);
And get the output of:
Type of a is: int
A possible use of this would be as follows:
#include <stdio.h>
#define indirect_print(a) print_##typeof(a)(a)
void print_int(int *i) {
printf("%d", *i);
}
void print_char(char *c) {
printf("%c", *c);
}
int main(void) {
char C = 'C';
int I = 100;
{
char *a = &C;
indirect_print(a);
}
{
int *a = &I;
indirect_print(a);
}
return 0;
}
If possible, it should work for all types including structures and unions, without relying on adding every type to a list manually.
Since C11, you can use a generic, see http://en.cppreference.com/w/c/language/generic. For example:
#define printType(a) printf("%s", _Generic( (a) , \
int : "int", \
long : "long", \
float : "float", \
default : "other type"))(a)
Every type that can be used needs to be listed.
In C++, there is also the typeid keyword:
#include <typeinfo>
#define printType(a) std::cout << typeid(a).name() << std::endl;
The preprocessor runs before the compiler. So all its replacements are performed before the actual compilation is started. typeof() is evaluated by the compiler, which would only see a string "typeof()" which will obviously not be evaluated.
So, the answer is: not for pre-C11. For C11, see the answer of #tmlen, but be aware there are some ambiguities about the _Generic type selectors which are resolved differently in different compilers, wich can result in problems with qualified types. There is a defect report about this issue, read Jens Gustedt's blob for details: https://gustedt.wordpress.com/2015/05/11/the-controlling-expression-of-_generic/#more-2256 (he also filed a defect report http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_423.htm).
Is is possible to convert any variable of any type to string?
I wrote the following
#define TO_STRING(val) #val
Is this a valid way of converting a variable into a string?
I think the code below will do your work. I uses the standard sprintf function, which prints data from any type to a string, instead to stdout. Code:
#include <stdio.h>
#define INT_FORMAT "%d"
#define FLOAT_FORMAT "%f"
#define DOUBLE_FORMAT "%lf"
#define LL_FORMAT "%lld"
// ect ...
#define CONVERT_TO_STRING(FORMAT, VARIABLE, LOCATION) \
do { \
sprintf(LOCATION, FORMAT, VARIABLE); \
} while(false)
int main() {
char from_int[30];
char from_float[30];
char from_double[30];
char from_ll[30];
CONVERT_TO_STRING(INT_FORMAT, 34, from_int);
CONVERT_TO_STRING(FLOAT_FORMAT, 34.234, from_float);
CONVERT_TO_STRING(DOUBLE_FORMAT, 3.14159265, from_double);
CONVERT_TO_STRING(LL_FORMAT, 9093042143018LL, from_ll);
puts(from_int);
puts(from_float);
puts(from_double);
puts(from_ll);
return 0;
}
You will get a string version of the variable's name, i.e. it will convert a to "a". The #when used like this is called the stringification operator.
For example:
#define TO_STRING(val) #val
int main(void)
{
const int a = 12;
print("a is %s\n", TO_STRING(a));
return 0;
}
This will print a is a.
What do you expect to happen?
You can't get the variable's value, of course, since that's not available when the pre-processor runs (which is at compile-time).
try this will work with integers: edit the format string for other data types.
sprintf(str,"%d",value);
I have
#define ADD 5
#define SUB 6
Can I print ADD and SUB given their values 5 and 6?
No.
The names of the defined symbols are removed by the preprocessor, so the compiler never sees them.
If these names are important at runtime, they need to be encoded in something more persistent than just preprocessor symbol names. Perhaps a table with strings and integers:
#define DEFINE_OP(n) { #n, n }
static const struct {
const char *name;
int value;
} operators[] = {
DEFINE_OP(ADD),
DEFINE_OP(SUB),
};
This uses the stringifying preprocessor operator # to avoid repetitions.
With the above, you can trivially write look-up code:
const char * op_to_name(int op)
{
size_t i;
for(i = 0; i < sizeof operators / sizeof *operators; ++i)
if(operators[i].value == op)
return operators[i].name;
return NULL;
}
you can do something like
printf("%d", ADD);
and it will print 5
The thing you have to remember about defines is:
Defines are substituted into the source code by the preprocessor before it is compiled so all instances of ADD in your code are substituted by 5. After the preprocessor the printf looks like this:
printf("%d", 5);
So to answer your question:
No you can't do it like that.
Yes, but not in via some reverse lookup mechanism wherein the value 5 is somehow symbolic in regards to the string "ADD". The symbols defined via a #define are tectually replaced by the pre-processor. You can however keep it simple:
const char *get_name(int value) {
switch(value) {
case ADD:
return "ADD";
case SUB:
return "SUB";
default:
return "WHATEVER";
}
}
#include <stdio.h>
int main() {
printf("%s = %d\n", get_name(ADD), ADD);
printf("%s = %d", get_name(SUB), SUB);
}
With modern C, since C99, this is even much simpler than unwind's answer by using designated initializers and compound literals
#define DEFINE_OP(n) [n] = #n
#define OPNAMES ((char const*const opNames[]){ \
DEFINE_OPT(ADD), \
DEFINE_OPT(SUB), \
})
inline
char const* getOp(unsigned op) {
size_t const maxOp = sizeof OPNAMES/ sizeof *OPNAMES;
if (op >= maxOp || !OPNAMES[op]) return "<unknown operator>";
else return OPNAMES[op];
}
Any modern compiler should be able then to expand calls as getOp(ADD) at compile time.