Search code examples
cc-preprocessorvariadic-functionsvariadic-macros

Is it possible to get macro passed as optional argument to variadic function using va_arg


I have the below program. It passes a macro as optional arg to variadic function. Within that function definition, shall we able to get that macro without expansion. I have used type as 'char *' and is showing the macro expanded string. Any ways to get macro as it is.

#include <stdio.h>
#include <stdarg.h>

#define CONN_DISALLOW 3201008
#define SYSLOG_CONN_DISALLOW  \
    "%d: Disallowing new connections. Reason: %s.\n", CONN_DISALLOW

void cp_syslog(int syslogid, ...);

void cp_syslog(int syslogid, ...)
{
        char *syslog_disallow;
        va_list ap;
        va_start(ap, syslogid);

        syslog_disallow = va_arg(ap, char *);

        printf("String is %s", syslog_disallow);
        printf("Macro is %s", SYSLOG_CONN_DISALLOW);

        va_end(ap);
}

int main()
{
        int id = 2;
        cp_syslog(id, SYSLOG_CONN_DISALLOW);
        return 0;
}

Now got the output as:

String is %d: Disallowing new connections. Reason: %s.
Macro is %d: Disallowing new connections. Reason: %s.

Expecting as:

String is SYSLOG_CONN_DISALLOW

My expectation here is how to process a particular macro if different macros are passed as optional argument to the same variadic func.

like below:

cp_syslog(id, SYSLOG_CONN_DISALLOW);
cp_syslog(id, SYSLOG_CONN_ALLOW);
cp_syslog(id, SYSLOG_ICMP_DISALLOW);

Solution

  • A first possibility is to just do

    cp_syslog(id, "SYSLOG_CONN_DISALLOW");
    

    Execution :

    pi@raspberrypi:/tmp $ ./a.out
    String is SYSLOG_CONN_DISALLOWMacro is %d: Disallowing new connections. Reason: %s.
    pi@raspberrypi:/tmp $ 
    

    (a newline is missed in the first printf or do cp_syslog(id, "SYSLOG_CONN_DISALLOW\n"))

    But this is artificial and even the definition of cp_syslog is artificial because that one knows the macro is SYSLOG_CONN_DISALLOW being in its definition.


    If you want to give to 'something else' both the name of a macro and its 'value' just use an intermediate macro like :

    #define NAME_VALUE(x) #x, x
    

    The expansion of NAME_VALUE(SYSLOG_CONN_DISALLOW) is "SYSLOG_CONN_DISALLOW", "%d: Disallowing new connections. Reason: %s.\n", 3201008

    That time cp_syslog does not have to know it applies on SYSLOG_CONN_DISALLOW :

    #include <stdio.h>
    #include <stdarg.h>
    
    #define CONN_DISALLOW 3201008
    #define SYSLOG_CONN_DISALLOW  \
        "%d: Disallowing new connections. Reason: %s.\n", CONN_DISALLOW
    
    #define NAME_VALUE(x) #x, x /* ADDED */
    
    void cp_syslog(int syslogid, ...);
    
    void cp_syslog(int syslogid, ...)
    {
      char *syslog_disallow;
      va_list ap;
      va_start(ap, syslogid);
    
      syslog_disallow = va_arg(ap, char *);
    
      printf("String is %s\n", syslog_disallow); /* \n ADDED */
      printf("Macro is %s", va_arg(ap, char *)); /* MODIFIED */
    
      va_end(ap);
    }
    
    int main()
    {
            int id = 2;
            cp_syslog(id, NAME_VALUE(SYSLOG_CONN_DISALLOW)); /* MODIFIED */
            return 0;
    }
    

    Compilation and executon :

    pi@raspberrypi:/tmp $ gcc pp.c
    pi@raspberrypi:/tmp $ ./a.out
    String is SYSLOG_CONN_DISALLOW
    Macro is %d: Disallowing new connections. Reason: %s.
    pi@raspberrypi:/tmp $