简体   繁体   中英

How to use va_arg to modify the value of a variadic parameter in C

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

void tag_log(const char *format, ...) {
    va_list ap;
    va_start(ap, format);
    for (int i = 0; i < 4; i++) {
        va_arg(ap, int) += 100; // is wrong?
    }
    va_end(ap);
    va_start(ap, format);
    vprintf(format, ap);
    va_end(ap);
}

int main() {
    tag_log("%d, %d, %d, %d\n", 1, 2, 3, 4);
}

Since va_arg returns an rvalue, the content cannot be modified. How to modify the content of the variable parameter?

Expected output: 101, 102, 103, 104

thanks!!!

How should i do?

Assume that you call:

int main() {
    tag_log("%d, %s, %d, %d\n", 1, "My precious values", 3, 4);
}

How will you deal with that in your tag_log() ? are you going to reinterpret the pointer passed to the string literal and adding 100 to it?

The answer to this question is "you cannot" ,

        va_arg(ap, int) += 100; // is wrong?

is equivalent to an rvalue (the result of a function value or a macro call, converted to a type specified in the second parameter to the macro call), so you cannot change it. An rvalue is just a value, without any reference to where it is stored. This is how parameters are passed to functions, and how values are returned from functions, but while explicit parameter declarations result in local variables (that can be used as lvalues and modified), the expression returned by the va_arg() macro is an rvalue, and so, you cannot change it (as you cannot change in a program the literal value 3 ) The situation is the same as if you had:

#define PARAMETER 3

and you say

    PARAMETER = 5;

(well, not exactly the same... but the effect is the same) even the statemente looks like a variable assignment, you have an rvalue ( 3 ) being assigned another rvalue( 5 ), in something like

    3 = 5;

Can you do this? nope.

But you have a solution... just create a local variable and assign it the value returned by va_arg.

    int var = va_arg(ap, int);
    var += 100;  // this is not wrong anymore.

or use the rvalue in the expression you want:

    whatever_int_variable = va_arg(ap, int) + 100;  // this is also valid.

If you consider that the "%s, %s, %s, %s\n" literal string should always be fixed, then it should be better for you to do:

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

void tag_log(int a, int b, int c, int d) {
   printf("%d, %d, %d, %d\n", a, b, c, d);
}

int main() {
    tag_log(1, 2, 3, 4);
}

but I imagine that what you want to do is to be as general as printf is, making all possible format strings.... then you need to dig into the body of printf and see how it solves each of the format specifiers and do the same in your function. You cand divide the work, by selecting all the format specifiers, and divide the string literal into places where literal strings are printed only, and separate all the format specifiers to individually call printf with each parameter, but the sample code you specified is not well specified, so I think is no worth considering to add 100 to break the string parameter to separate the literal formats from the format specifiers and add 100 to all the integer parameters, or to add 100.0 to the double , what should we do with the string literals, or with the booleans?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM