Srinadh kch
Srinadh kch

Reputation: 33

How to make a variable value passage for preprocessor?

Here I know that the following code simply copies the character i rather than its value to the preprocessor statement (which makes a error for undefined symbol i in compile-time).

What I want is:

Is their a way such that the compiler treats, i as a variable with some value rather than a character ?

#include <stdio.h>

#define PRINT(x) printf("%d \n", y ## x)

int main(void) {  
    int y1=0 , y2=1 , y3=4;

    for(int i=1; i <= 3; ++i) {          
        PRINT(i);
    }
    return 1;
}

Upvotes: 2

Views: 155

Answers (2)

Antoine
Antoine

Reputation: 14104

About the pre-processor

First of all, I think there's a need to clarify how the preprocessor works: it pre-processes the input files, which means it runs before the compiler. Unfortunatly, for historical reasons, it doesn't know anything about C or C++, doesn't parse anything, and just does very simple textual operations on words and parenthesis. Just to illustrate my point:

#define this __FILE__
#define file -- Hell no!
#define fine(a, b) fine: a ## _ ## b
Ok, so this is not a valid C or C++ file
But the preprocessor will run just fine(go, try!)

Run this with a pre-processor, for example gcc -x c -E -P test.txt and you'll get:

Ok, so "test.txt" is not a valid C or C++ -- Hell no!
But the preprocessor will run just fine: go_try!

So, obviously, when the preprocessor sees PRINT(i) in your code, it replaces it with printf("%d \n", yi) without thinking much about it. And it has absolutely no idea i is a variable, don't even think about evaluating it's value.

Solutions

Basically, what you want is print a bunch of numbers.

  1. You could simply do

    printf("0\n1\n4\n");
    

    But this lacks makes changing numbers cumbersome,

  2. so let's go with

    printf("%d\n%d\n%d\n", 0, 1, 4);
    

    Which makes it easy to change a number, but not to add/remove one.

  3. Ok so how about:

    printf("%d\n", 0);
    printf("%d\n", 1);
    printf("%d\n", 4);
    

    Yeah, you can change/add/remove numbers easily but as any sane programmer you hate repetition. So, we need some kind of loop.

  4. By far the simplest and most straightforward way to iterate in C is at runtime, using an array:

    int [] y = { 0, 1, 4 };
    for(int i = 0; i < sizeof(y)/sizeof(int); ++i) {
        printf("%d\n", y[i]);
    }
    
  5. If you want, you can hide the printf using a function:

    inline void print_int(int* y, int i) { print_int(y[i]); }
    int [] y = { 0, 1, 4 };
    for(int i = 0; i < sizeof(y)/4; ++i) print_int(y, i);
    
  6. And going further with functions:

    inline void print_int(int x)           { printf("%d\n", x); }
    inline void print_int(int* y, int i)   { print_int(y[i]); }
    inline void print_ints(int * y, int n)
    {
        for(int i = 0; i < n; ++i)
            print_int(y, i);
    }
    template<int n> // C++
    inline void print_ints(const int[n] & y) { print_ints(&y[0], n); }
    
    int [] y = { 0, 1, 4 };
    print_ints(y); // C++
    
    // or in C:
    print_ints(y, sizeof(y)/sizeof(int));
    

    Now, what if you absolutely want the generated code to look like solution 3. ? This means you need the iteration to happen at compile-time. Tricky!

  7. That's where the preprocessor can come into play. There are (hacky) ways to make it do this kind of things. I strongly recommend not implementing this yourself (except to play), but use the Boost.preprocessor library instead:

    #define PRINTER(R,D, NUMBER) printf("%d\n", NUMBER);
    
    #define NUMBERS (0, 1, 4)
    BOOST_PP_LIST_FOR_EACH(PRINTER, _, BOOST_PP_TUPLE_TO_LIST(NUMBERS))
    // will expand to printf("%d\n", 0); printf("%d\n", 1); printf("%d\n", 4);
    

Upvotes: 4

Drew McGowen
Drew McGowen

Reputation: 11716

Under standard C, this is not possible; during preprocessing, the compiler simply sees the identifier i as simply that - an identifier. It does not know that i is of type int, or that it's even a variable in the first place.

The easiest way to achieve what's intended is to use an array, like so:

int i;
int y[] = { 0, 1, 4 };

for (i = 0; i < 3; i++) // NOTE: arrays in C start at index 0, not 1
{
    printf("%d \n", y[i]);
}

Also note that I got rid of the macro, as you want to use the value of a runtime variable i to select another runtime variable.

Upvotes: 0

Related Questions