Search code examples
c++variadic-functionsparentheses

Difference between variadic parameters with and without parentheses


Why using parentheses in the first code works and the second doesn't?

In the first code I'm using only variadic parameter with parentheses and the seconde one have a Integer parameter with a variadic, if I use parentheses when I call the function it won't work.

#include <bits/stdc++.h>

void func( char* szFormat, ... );

#define M1(a)  M2(a)
#define M2(b) func b

int main()
{
    M1(("Hello %s %d\n", "world",2015)); // this works
    return 0;
}

void func( char* szFormat, ... )
{
    char      trace_str[1000];
    va_list   arg_list;
    std::string str;

    va_start(arg_list, szFormat);
    vsprintf(trace_str, szFormat, arg_list);
    va_end(arg_list);

    str += trace_str;
    std::cout << str << std::endl;
}

This code below doesn't work using parentheses.

#include <bits/stdc++.h>

void func( int year, char* szFormat, ... );

#define M1(a,...)  M2(a, __VA_ARGS__)
#define M2 func 

int main()
{
 // M1(2015, ("Hello %s", "world")); // this doesn't works
    M1(2015, "Hello %s", "world");   // this way works
    return 0;
}

void func(int year, char* szFormat, ... )
{
    char      trace_str[1000];
    va_list   arg_list;
    std::string str;


    va_start(arg_list, szFormat);
    vsprintf(trace_str, szFormat, arg_list);
    va_end(arg_list);

    str += trace_str;
    std::cout << str << " " << year << std::endl;

}

Thanks everyone!


Solution

  • It is enough to see preprocess output to understand that.

    Input file:

    void func( int year, char* szFormat, ... );
    
    #define M1(a,...)  M2(a, __VA_ARGS__)
    #define M2 func 
    
    int main()
    {
        M1(2015, ("Hello %s", "world")); // this doesn't works
        M1(2015, "Hello %s", "world");   // this way works
        return 0;
    }
    

    output of c++ -E foo.cpp:

    # 1 "ess.cpp"
    # 1 "<built-in>" 1
    # 1 "<built-in>" 3
    # 155 "<built-in>" 3
    # 1 "<command line>" 1
    # 1 "<built-in>" 2
    # 1 "ess.cpp" 2
    void func( int year, char* szFormat, ... );
    
    
    
    
    int main()
    {
        func(2015, ("Hello %s", "world"));
        func(2015, "Hello %s", "world");
        return 0;
    }
    

    The relevant part is here:

        M1(2015, ("Hello %s", "world")); // this doesn't works
        M1(2015, "Hello %s", "world");   // this way works
    
        func(2015, "Hello %s", "world");
        func(2015, "Hello %s", "world");
    

    The macro is only interpreted by the preprocessor. If you put two parentheses levels, you get one extra in the function call, and it does not give expected result. Here compiler will just see the comma operator in the inner bloc, would see a void evaluataion or "Hello %s" followed with "world" and it will end in func(2015, "world");. But func(2015, ("Hello %d", 12)); would end in func(2015, 10); with a syntax error no known conversion from 'int' to 'char *' for 2nd argument


    In first code, you had #define M2(b) func b that removed one parentheses level, so

    M1(("Hello %s %d\n", "world",2015));
    

    was (correctly) preprocessed as

    func ("Hello %s %d\n", "world",2015);