ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
off-topic, but here is the definition of va_list on x86_64:
Code:
typedef struct __va_list_tag {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} va_list[1];
It being a typedef-ed array in x86-64, and pointer in other platforms; sometime it is hard to create platform independent code if you have to pass va_list between function. My little hack:
Uh? I don't understand why you need that. You can just pass va_list directly by value and since it's an array, pointer to its first argument will be the value passed.
Well, you are right, it would compile and run; the problem arises when both functions (caller and callee) wishes to fetch from the same va_list: the result will be different in x86 ('ap' is a pointer that is copied when passed as parameter) and in x86-64 ('ap' is an array, it's address is passed as parameter). If you would want to pass 'va_list *' instead to fix this, you would get compilation problems in 64-bit mode.
$ ./va32
function2: int arg=1
function1: int arg=1
function2: int arg=2
function1: int arg=2
$ ./va64
function2: int arg=1
function1: int arg=2
function2: int arg=3
function1: int arg=4
Well, you are right, it would compile and run; the problem arises when both functions (caller and callee) wishes to fetch from the same va_list: the result will be different in x86 ('ap' is a pointer that is copied when passed as parameter) and in x86-64 ('ap' is an array, it's address is passed as parameter). If you would want to pass 'va_list *' instead to fix this, you would get compilation problems in 64-bit mode.
There is a thing va_copy is good for: ensure the behaviour I presented with 'va32': create an independent copy of 'ap' so that both instances of it could be read independently.
But if you want the other behaviour (presented with 'va64'), i.e. both function read from the same argument-list, it doesn't help.
Example for such usage:
Code:
int vsprintf (char *to, const char *fmt, va_list ap)
{
char *p= to;
...
case 'd':
p += vsprintf_int (p, fmtopts, ap); break;
/* depending on fmtopts, reads 1 or 2 arguments from 'ap' */
case 's':
p += vsprintf_str (p, fmtopts, ap); break;
/* depending on fmtopts, reads 1,2 or 3 arguments from 'ap' */
...
return (int)(p-to);
}
PS: Most likely I have already heard of 'va_copy', because I did use it in my post #20.
If you want functions to use the same argument list you just pass the va_list argument. I'm just confused about what you're trying to accomplish that cannot be done with va_copy ore passing va_list around:
Code:
#include <stdarg.h>
#include <stdio.h>
static void f(unsigned n, va_list ap) {
printf("f: %d: %s\n", n, va_arg(ap, const char *));
}
static void g(unsigned n, va_list ap) {
va_list ap2;
va_copy(ap2, ap);
printf("g: %d: %s\n", n, va_arg(ap2, const char *));
va_end(ap2);
}
static void func(unsigned n, ...) {
unsigned i;
va_list ap;
va_start(ap, n);
for (i = 0; i < n; ++i) {
if (i % 2)
g(i, ap);
f(i, ap);
}
va_end(ap);
}
int main(void) {
func(4, "foo", "bar", "baz", "qux");
return 0;
}
Code:
f: 0: foo
g: 1: bar
f: 1: bar
f: 2: baz
g: 3: qux
f: 3: qux
Off-topic of off-topic: There was a similar (a little bit similar) problem in OpenSsl's DES functionality:
older version typedefed array 'des_key_schedule',
newer version typedefed struct 'DES_key_schedule', and for compatility also struct 'des_key_schedule'.
I had to pass 'des_key_schedule' between functions, so I couldn't create a version that compiled without warnings with both OpenSsl versions. My only idea to maintain compatibility was this:
I know it's late, but it is related: when passing a 'va_list' as a variadic function-parameter (which is rare, I admit), va_copy isn't our friend (at least with AMD64/Linux/gcc|clang)
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.