Search code examples
cenumsmacrosconstantsprintf

Using Macro Constant in Printf Value


I'm currently creating a program that takes a CSV file, parses it, then prints out the various items on the page. Eventually, you'd have various columns of data. In order to have the columns looking nicely, you'd have to add padding to the fprintf() statement (at least I can't think of another way of doing it). The below is a snippet from my code:

    for (int pos = 0; pos < size; pos++) {
        fprintf(stdout, "%30s - %20d, %20d, %20s, %20d, %20d\n", 
                (char *)(item+pos)->itemval, (item+pos)->column, 
                (item+pos)->row, (char *)(item+pos)->columntitle, 
                (item+pos)->adjustedpos, (item+pos)->adjustedcolumn,
                (item+pos)->adjustedrow);
    }

Is it possible to use a macro constant as the padding? For example, in the printf() statement, can I have something like fprintf(..., "%'COLUMNMACROCONSTANT's", ...), which is defined in a macro? I apologize if this question has been asked before, but I don't know how to describe that part of the fprintf() function. I tried to just put it in, but it won't let me, which makes sense (how does the compiler know to separate the macro from the string). I'm wondering if there's some kind of separator like "\" for macros contained in this area of the print function.


Solution

  • If the macro is a simple decimal numeral, just digits, you can insert it into a string literal by using a macro to convert it to a string. Due to the order in which parts of macro replacement operate, you need two macros to do this. In the first, the macro parameter is replaced with the argument and a second macro is invoked:

    #define Stringize(x)        StringizeHelper(x)
    

    In the second, the argument is converted to a string literal:

    #define StringizeHelper(x)  #x
    

    So this program will print y in a field of 10 spaces, with an x before the field and a z after the field to mark the ends:

    #define Width   10
    
    #define StringizeHelper(x)  #x
    #define Stringize(x)        StringizeHelper(x)
    
    #include <stdio.h>
    
    int main(void)
    {
        printf("x%" Stringize(Width) "sz\n", "y");
    }
    

    Output:

    x         yz
    

    You can also specify the field width by putting * in the conversion specification, as in %*s, and passing the width as an argument to printf. This program produces the same output:

    #define Width   10
    
    #include <stdio.h>
    
    int main(void)
    {
        printf("x%*sz\n", Width, "y");
    }
    

    That methods works as long as Width is any int expression; it does not have to be a constant.