2
#include <stdio.h>
#define Type int

int main()
{
        Type x=3;
        printf("%d",x);
        return 0;

}

The code is simple and works fine. My question is, if I change #define Type int to #define Type float so , I have to change %d to %f as well. Is there any way to have a generic specifier, that would work for all int, float, char, string etc... So that, if I change #define Type int then I don't have to change the format specifiers within printf() function?

askmish
  • 6,464
  • 23
  • 42

2 Answers2

5

This is what I suggest:

#include <stdio.h>

#define TYPE int
#define TYPE_FORMAT "%d"

int main()
{
    TYPE x=3;
    printf("Value of x is: " TYPE_FORMAT "\n", x);
    return 0;
}

There is no way to make printf() auto-detect types in C. In C++, you can use the overloaded << operator, and that does figure out the types automatically, but C has nothing like it.

But you can #define a format as well as a type, and if you put multiple string literals next to each other the C compiler will auto-merge them into a single string constant.

P.S. Instead of using #define for the type, you should probably use typedef like so:

typedef int TYPE;

This means that in the debugger, you can see that your variable x is of type TYPE, while with the #define you would see it as type int.

And in a perfect world you would declare the format string like so:

static char const * const TYPE_FORMAT = "%d";

But we do not live in a perfect world. If you do the above declaration for TYPE_FORMAT, the compiler is probably not smart enough to merge the string in with other string literals. (I tried it with GCC, and as I expected I got an error message.) So for the TYPE_FORMAT you absolutely should use the #define.

Summary: use the typedef for the type but use the #define for the format.

steveha
  • 74,789
  • 21
  • 92
  • 117
2

With the new C standard C11 you could use type generic expressions like this one

#define MYFORMAT(X) \
_Generic(+(X)       \
   int: "%d",       \
   float: "%g",     \
   double: "%g",    \
   ... whatever ... \
)

and then use this as

printf("the value is " MYFORMAT(x), x);

The latest version of the clang compiler implements _Generic already, so there is no excuse to not use it anymore.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • 1
    "...there is no excuse to not use it anymore" because one compiler has it? I don't know about you, but I need to write code that compiles under GCC, Microsoft C, and various DSP compilers (ADI, TI, etc.) in addition to Clang. I'm happy to see this, but I won't be able to use it for quite some time. – steveha Aug 02 '12 at 20:24
  • Should have put a smiley there :) BTW gcc already has extensions that can be used to emulate `_Generic`, but with MS your screwed, they don't even support C99. – Jens Gustedt Aug 02 '12 at 20:27
  • 1
    "[MS] don't even support C99" Oh, don't I know it! Some things you can work around (like `typedef __int32 int32t;`) but some things are just broken. The one I really miss is designated union initializers. :-( – steveha Aug 02 '12 at 20:31