Passing variable number of arguments around

前端 未结 11 640
我寻月下人不归
我寻月下人不归 2020-11-22 07:16

Say I have a C function which takes a variable number of arguments: How can I call another function which expects a variable number of arguments from inside of it, passing a

相关标签:
11条回答
  • 2020-11-22 07:33

    You can try macro also.

    #define NONE    0x00
    #define DBG     0x1F
    #define INFO    0x0F
    #define ERR     0x07
    #define EMR     0x03
    #define CRIT    0x01
    
    #define DEBUG_LEVEL ERR
    
    #define WHERESTR "[FILE : %s, FUNC : %s, LINE : %d]: "
    #define WHEREARG __FILE__,__func__,__LINE__
    #define DEBUG(...)  fprintf(stderr, __VA_ARGS__)
    #define DEBUG_PRINT(X, _fmt, ...)  if((DEBUG_LEVEL & X) == X) \
                                          DEBUG(WHERESTR _fmt, WHEREARG,__VA_ARGS__)
    
    int main()
    {
        int x=10;
        DEBUG_PRINT(DBG, "i am x %d\n", x);
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-22 07:39

    I'm unsure if this works for all compilers, but it has worked so far for me.

    void inner_func(int &i)
    {
      va_list vars;
      va_start(vars, i);
      int j = va_arg(vars);
      va_end(vars); // Generally useless, but should be included.
    }
    
    void func(int i, ...)
    {
      inner_func(i);
    }
    

    You can add the ... to inner_func() if you want, but you don't need it. It works because va_start uses the address of the given variable as the start point. In this case, we are giving it a reference to a variable in func(). So it uses that address and reads the variables after that on the stack. The inner_func() function is reading from the stack address of func(). So it only works if both functions use the same stack segment.

    The va_start and va_arg macros will generally work if you give them any var as a starting point. So if you want you can pass pointers to other functions and use those too. You can make your own macros easily enough. All the macros do is typecast memory addresses. However making them work for all the compilers and calling conventions is annoying. So it's generally easier to use the ones that come with the compiler.

    0 讨论(0)
  • 2020-11-22 07:45

    Let's say you have a typical variadic function you've written. Because at least one argument is required before the variadic one ..., you have to always write an extra argument in usage.

    Or do you?

    If you wrap your variadic function in a macro, you need no preceding arg. Consider this example:

    #define LOGI(...)
        ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
    

    This is obviously far more convenient, since you needn't specify the initial argument every time.

    0 讨论(0)
  • 2020-11-22 07:49

    Short answer

    /// logs all messages below this level, level 0 turns off LOG 
    #ifndef LOG_LEVEL
    #define LOG_LEVEL 5  // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose
    #endif
    #define _LOG_FORMAT_SHORT(letter, format) "[" #letter "]: " format "\n"
    
    /// short log
    #define log_s(level, format, ...)     \                                                                                  
        if (level <= LOG_LEVEL)            \                                                                                     
        printf(_LOG_FORMAT_SHORT(level, format), ##__VA_ARGS__)
    
    

    usage

    log_s(1, "fatal error occurred");
    log_s(3, "x=%d and name=%s",2, "ali");
    

    output

    [1]: fatal error occurred
    [3]: x=2 and name=ali
    

    log with file and line number

    const char* _getFileName(const char* path)
    {
        size_t i = 0;
        size_t pos = 0;
        char* p = (char*)path;
        while (*p) {
            i++;
            if (*p == '/' || *p == '\\') {
                pos = i;
            }
            p++;
        }
        return path + pos;
    }
    
    #define _LOG_FORMAT(letter, format)      \                                                                        
        "[" #letter "][%s:%u] %s(): " format "\n", _getFileName(__FILE__), __LINE__, __FUNCTION__
    
    #ifndef LOG_LEVEL
    #define LOG_LEVEL 5 // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose
    #endif
    
    /// long log
    #define log_l(level, format, ...)     \                                                                               
        if (level <= LOG_LEVEL)            \                                                                                         
        printf(_LOG_FORMAT(level, format), ##__VA_ARGS__)
    

    usage

    log_s(1, "fatal error occurred");
    log_s(3, "x=%d and name=%s",2, "ali");
    

    output

    [1][test.cpp:97] main(): fatal error occurred
    [3][test.cpp:98] main(): x=2 and name=ali
    

    custom print function

    you can write custom print function and pass ... args to it and it is also possible to combine this with methods above. source from here

    int print_custom(const char* format, ...)
    {
        static char loc_buf[64];
        char* temp = loc_buf;
        int len;
        va_list arg;
        va_list copy;
        va_start(arg, format);
        va_copy(copy, arg);
        len = vsnprintf(NULL, 0, format, arg);
        va_end(copy);
        if (len >= sizeof(loc_buf)) {
            temp = (char*)malloc(len + 1);
            if (temp == NULL) {
                return 0;
            }
        }
        vsnprintf(temp, len + 1, format, arg);
        printf(temp); // replace with any print function you want
        va_end(arg);
        if (len >= sizeof(loc_buf)) {
            free(temp);
        }
        return len;
    }
    
    0 讨论(0)
  • 2020-11-22 07:50

    Variadic Functions can be dangerous. Here's a safer trick:

       void func(type* values) {
            while(*values) {
                x = *values++;
                /* do whatever with x */
            }
        }
    
    func((type[]){val1,val2,val3,val4,0});
    
    0 讨论(0)
提交回复
热议问题