How to count the number of arguments passed to a function that accepts a variable number of arguments?

前端 未结 10 2078
旧时难觅i
旧时难觅i 2020-12-01 05:18

How to count the no of arguments passed to the function in following program:

#include
#include
void varfun(int i, ...);
int m         


        
相关标签:
10条回答
  • 2020-12-01 05:45

    In this code it is possible when you pass only pointer

    # include <unistd.h>
    # include <stdarg.h>
    # include <string.h>
    # include <errno.h>
    
    size_t __print__(char * str1, ...);
    # define print(...) __print__(NULL, __VA_ARGS__, NULL)
    # define ENDL "\n"
    
    int main() {
    
      print("1", ENDL, "2", ENDL, "3", ENDL);
    
      return 0;
    }
    
    size_t __print__(char * str1, ...) {
        va_list args;
        va_start(args, str1);
        size_t out_char = 0;
        char * tmp_str;
        while((tmp_str = va_arg(args, char *)) != NULL)
            out_char = out_char + write(1, tmp_str,strlen(tmp_str));
        va_end(args);
        return out_char;
    }
    
    0 讨论(0)
  • 2020-12-01 05:54

    You could also use a meaningful value that indicates end of arguments. Like a 0 or -1. Or a max type size like 0xFFFF for a ushort.

    Otherwise, you need to mention the count upfront or make it deductible from another argument (format for printf() like functions).

    0 讨论(0)
  • 2020-12-01 05:55

    You can't. You have to manage for the caller to indicate the number of arguments somehow. You can:

    • Pass the number of arguments as the first variable
    • Require the last variable argument to be null, zero or whatever
    • Have the first argument describe what is expected (eg. the printf format string dictates what arguments should follow)
    0 讨论(0)
  • 2020-12-01 05:55

    The safest way is as described above. But if you REALLY need to know the number of arguments without adding the extra argument mentioned then you can do it this way (but note that it is very machine dependent, OS dependent and even, in rare cases, compiler dependent). I ran this code using Visual Studio 2013 on a 64 bit DELL E6440.

    Another point, at the point where I divided by sizeof(int), that was because all of my arguments were int's. If you have different size arguments, there my need to be some adjustment there.

    This relies on the calling program to use the standard C calling convention. (varfun() gets the number of arguments from the "add esp,xxx" and there are two forms of the add, (1) short form and (2) long form. In the 2nd test I passed a struct because I wanted to simulate lots of arguments to force the long form).

    The answers printed will be 6 and 501.

        varfun(1, 2, 3, 4, 5, 6);
    00A03CC8 6A 06                push        6  
    00A03CCA 6A 05                push        5  
    00A03CCC 6A 04                push        4  
    00A03CCE 6A 03                push        3  
    00A03CD0 6A 02                push        2  
    00A03CD2 6A 01                push        1  
    00A03CD4 E8 E5 D3 FF FF       call        _varfun (0A010BEh)  
    00A03CD9 83 C4 18             add         esp,18h  
        varfun(1, x);
    00A03CDC 81 EC D0 07 00 00    sub         esp,7D0h  
    00A03CE2 B9 F4 01 00 00       mov         ecx,1F4h  
    00A03CE7 8D B5 28 F8 FF FF    lea         esi,[x]  
    00A03CED 8B FC                mov         edi,esp  
    00A03CEF F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
    00A03CF1 6A 01                push        1  
    00A03CF3 E8 C6 D3 FF FF       call        _varfun (0A010BEh)  
    00A03CF8 81 C4 D4 07 00 00    add         esp,7D4h 
    
    
    
    #include<stdio.h>
    #include<stdarg.h>
    void varfun(int i, ...);
    int main()
    {
        struct eddy
        {
            int x[500];
        } x = { 0 };
        varfun(1, 2, 3, 4, 5, 6);
        varfun(1, x);
        return 0;
    }
    
    void varfun(int n_args, ...)
    {
        va_list ap;
        unsigned long *p;
        unsigned char *p1;
        unsigned int nargs;
        va_start(ap, n_args);
        p = (long *)(ap - _INTSIZEOF(int) - _INTSIZEOF(&varfun));
        p1 = (char *)*p;
        if (*p1 == 0x83)     // short add sp,x
        {
            nargs = p1[2] / sizeof(int);
        }
        else
        {
            nargs = *(unsigned long *)(p1+2) / sizeof(int);
        }
        printf("%d\n", nargs);
        va_end(ap);
    }
    
    0 讨论(0)
提交回复
热议问题