Home > Blockchain >  why called function can get arguments of parent-function by va_start()?
why called function can get arguments of parent-function by va_start()?

Time:09-04

I implemented a function with variable arguments below:

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

#define ERR_BUFFER_SIZE 4096

void errPrint(const char *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

    char buf[ERR_BUFFER_SIZE];
    vsnprintf(buf, sizeof(buf), format, argptr);
    fprintf(stderr, "%s", buf);
    
    va_end(argptr);
}

Then I hope to implement another named "errExit()" based on the function above. I just tried like below.It works as I hoped but I dont't think it correct.

void errExit(const char *format, ...)
{
    errPrint(format);
    exit(EXIT_FAILURE);
}

I tried errExit("hello,%s,%s,%s", "arg1","arg2", "arg3"); and it printed "hello,arg1,arg2,arg3" correctly.

But after I added two line code like below, it throwed error Segmentation fault.

void errExit(const char *format, ...)
{
    char buf[4096];//added
    strcpy(buf, format);//added
    
    errPrint(format);
    exit(EXIT_FAILURE);
}

I am very confused. According to what I learned:

  1. There is only one argument format in the stack of called function errPrint(). I can't believe va_start() will get arguments from the its parent-function errExit().
  2. Since errPrint() works "correctly", why it doesn't work after I add the two lines code? It seems that the code added have no effect.

(My English is not well, hoping you everyone can stand my statement. Thank you! )

CodePudding user response:

In errExit() you need to pass the variable arguments to another function via a va_list argument. As you were not vsnprintf will eventually crash when trying to access non-existing arguments on the stack.

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

#define ERR_BUFFER_SIZE 4096

void verrPrint(const char *format, va_list ap) {
    char buf[ERR_BUFFER_SIZE];
    vsnprintf(buf, sizeof(buf), format, ap);
    fprintf(stderr, "%s", buf);
}

void errPrint(const char *format, ...) {
    va_list ap;
    va_start(ap, format);
    verrPrint(format, ap);
    va_end(ap);
}

void errExit(const char *format, ...) {
    va_list ap;
    va_start(ap, format);
    verrPrint(format, ap);
    va_end(ap);
    exit(EXIT_FAILURE);
}

int main(void) {
    errPrint("What is the meaning of %s\n", "life?");
    errExit("%d\n", 42);
    return 0;
}

CodePudding user response:

Thank you everyone.I have learned your from your answers. I choose to change my code like below.

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

#define ERR_BUFFER_SIZE 4096

void errPrint(const char *format, va_list arg_list)
{
    char buf[ERR_BUFFER_SIZE];
    vsnprintf(buf, sizeof(buf), format, arg_list);
    fprintf(stderr, "%s", buf);
}

void errExit(const char *format, va_list arg_list)
{
    errPrint(format, arg_list);
    exit(EXIT_FAILURE);
}

void v_exec(void (*func)(const char *, va_list), const char *format, ...)
{
    va_list arg_list;
    va_start(arg_list, format);

    func(format, arg_list);

    va_end(arg_list);
}

int main(void) 
{ 
    v_exec(errExit,"%s%d", "hello",520);
    return 0;
}
  • Related