1

I'm trying to write a somehow-generic printArray function in C, which I will able to run with several programs, each with a different type of array. I did this:

#define TYPE int /* or char or double*/

void printArray(TYPE *a, int size){
    for (int i=0; i<size; i++){
#if TYPE == int
        printf("%d ", a[i]);
#elif TYPE == char
        printf("%c ", a[i]);
#elif TYPE == double
        printf("%f ", a[i]);
#endif
    }
    printf("\n");
}

I have tried running it, but no matter what TYPE is defined to be, the first #if always checks in, meaning - if the if's are written:

#if TYPE == int
        printf("int");
#elif TYPE == char
        printf("char");
#elif TYPE == double
        printf("double");
#endif

then it will print "int", even if TYPE is defined to be char, and if

#if TYPE == char
        printf("char");
#elif TYPE == int 
        printf("int");
#elif TYPE == double
        printf("double");
#endif

then it will print "char", even if TYPE is defined to be int, etc.

ideas?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Itay Hazan
  • 15
  • 4
  • 1
    Among lots of other things in C, the preprocessor ain't magic. Don't have expectations/make assumptions. –  Mar 28 '13 at 10:10
  • in C++ the right way of doing this is to use `std::cout << a[i]` using the iostream library – FKaria Mar 28 '13 at 10:10
  • The comparison operators functions like the normal C (or C++) comparison operators, it can't compare "strings" like you try to do. – Some programmer dude Mar 28 '13 at 10:11
  • Your question's body says you're writing C, but you tagged both C and C++. Please pick one, the correct is entirely different between the two languages. – jrok Mar 28 '13 at 10:13
  • I misread the original question, so I deleted my answer which didn't really answer the question. – Randy Howard Mar 28 '13 at 10:14
  • @JoachimPileborg It's even more restrictive than the C++ comparison operators. I don't think floating point comparisons are supported, for example. – James Kanze Mar 28 '13 at 10:18

5 Answers5

6

Preprocessor #if evaluates integer expressions. You're trying to treat == as if it were comparing tokens. Since int, char, double, etc. are not defined as preprocessor variables, they all evaluate as 0.

You could do

#define TYPE int
#define FMT "%d"

void printArray(TYPE *a, int size){
    for (int i=0; i<size; i++)
        printf(FMT " ", a[i]);

    printf("\n");
}

Much simpler, and it works.

If you want to only have to specify the TYPE, you could do something like

#define FMT_int "%d"
#define FMT_char "%c"
#define FMT_double "%f"
#define FMT PPCAT(FMT_, TYPE)

where PPCAT is defined in my answer to C/C++ Macro string concatenation

Community
  • 1
  • 1
Jim Balter
  • 16,163
  • 3
  • 43
  • 66
4

The C and C++ preprocessor can only work with numbers (numeric literals, to be exact). In expressions, any words it doesn't recognize (after all macro expansion) are treated as a 0.

You'd need to do something like this:

#define TYPE_int 0
#define TYPE_char 1
#define TYPE_double 2

#define TYPE_USED TYPE_int

#if TYPE_USED == TYPE_int
typedef int TYPE;
#elif TYPE_USED == TYPE_char
typedef char TYPE;
#elif TYPE_USED == TYPE_double
typedef double TYPE;
#endif

void printArray(TYPE *a, int size){
    for (int i=0; i<size; i++){
#if TYPE_USED == TYPE_int
        printf("%d ", a[i]);
#elif TYPE_USED == TYPE_char
        printf("%c ", a[i]);
#elif TYPE_USED == TYPE_double
        printf("%f ", a[i]);
#endif
    }
    printf("\n");
}

You could use boost.preprocessor to do some metaprogramming magic with preprocessor loops instead of listing all the values manually.

Of course, the above code applies to C. If you're using C++, use a template instead of macro hacks and std::cout instead of printf().

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
1

You should avoid the pre-processor wherever possible, and this is a classic example of when to avoid it! If you need to write code that depends on type then you can use either template, inheritance or polymorphism for this.

In this case you can rewrite printArray as a template function:

template<class T>
void printArray(T *data, int count)
{
  for(int i=0; i<count; i++)
  {
    cout << data[i] << " ";
  }

  cout << endl;
}
Sean
  • 60,939
  • 11
  • 97
  • 136
  • `std::cout` is much better than `printf`. – Zyx 2000 Mar 28 '13 at 10:13
  • 1
    This is probably what they really want, but it's slightly different to what they're trying. The will only ever have one function defined with the type determined by `TYPE`. – Joseph Mansfield Mar 28 '13 at 10:13
  • @sftrabbit Unless they put their function in a header file which they include after the #define. I've got a whole library of such things from back when there weren't much much much better languages around. – Jim Balter Mar 28 '13 at 10:28
  • 2
    "can use either template, inheritance or polymorphism for this" -- None of those can be used because this question has a C tag. – Jim Balter Mar 28 '13 at 10:30
  • 1
    @JimBalter It also had a C++ tag originally; the answer was probably added before the tag was removed. – Angew is no longer proud of SO Mar 28 '13 at 11:33
  • @Angew I know, but my point still holds. Answers should be updated to be in sync with changes to questions ... SO is forever. – Jim Balter Mar 28 '13 at 20:43
1

Preprocessor evaluation is more or less like C++ evaluation. It is numeric (despite the fact that the preprocessor works with text). Any preprocessor symbol which remains after macro expansion is replaced by 0, and C++ keywords are still symbols in the preprocessor. (There is a special exception for the preprocessor symbol true, which expands to 1.) So in the end, all of your comparisons come out to 0 == 0, which is always true.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

http://msdn.microsoft.com/en-us/library/ew2hz0yd(v=VS.80).aspx

The constant-expression is an integer constant expression with some additional restrictions.

It seems u can't compare strings. Try the following:

#define TYPE_int /* put this too */
#define TYPE int /* or char or double*/
void printArray(TYPE *a, int size){
    for (int i=0; i<size; i++){
#ifdef TYPE_int
        printf("%d ", a[i]);
#elif defined TYPE_char
        printf("%c ", a[i]);
#elif defined TYPE_double
        printf("%f ", a[i]);
#endif
    }
    printf("\n");
}
Lefteris E
  • 2,806
  • 1
  • 24
  • 23