LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-25-2014, 12:24 PM   #16
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081

Quote:
Originally Posted by doughyi8u View Post
I must be missing something b/c I thought that s would get one string out of the argv parameter passed in to the function as a va_arg.
It gets one argument out the arguments you passed to the function, which is argv (not argv's contents) in this case.
 
Old 08-25-2014, 01:28 PM   #17
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
Code:
static void testfun (const char *fmt, ...)
{
   const char *p= fmt-1;
   va_list ap;
   int n;
   const char *s;

   va_start (ap, fmt);

   while (*++p) {
      switch (*p) {
      case 'd':
          n= va_arg (ap, int);
          printf ("integer param: %d\n", n);
          break;
      case 's':
          s= va_arg(ap, char *);
          printf ("string param: %s\n", s);
          break;
      default:
          printf ("*** unimplemented '%c'\n", *p);
          break;
      }
   }
   va_end(ap);
}

int main (void)
{
    testfun ("sds", "param1str", 2, "param3str");
    return 0;
}
 
Old 08-26-2014, 06:09 AM   #18
a4z
Senior Member
 
Registered: Feb 2009
Posts: 1,727

Rep: Reputation: 742Reputation: 742Reputation: 742Reputation: 742Reputation: 742Reputation: 742Reputation: 742
Wink

Quote:
Originally Posted by doughyi8u View Post
I'm trying to grasp va_arg
great, and when you are done start with
why C++ does not need C style va_args,
and
why you should run away when you see someone using them
 
Old 08-26-2014, 09:46 AM   #19
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
Quote:
Originally Posted by NevemTeve View Post
Code:
/* works on x86, doesn't work on x86-64 */
This is because the x86_64 ABI uses registers to pass the first few arguments even for ... functions.
 
Old 08-26-2014, 10:07 AM   #20
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
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:

Code:
typedef struct va_list_struct {
    va_list ap;>/* platform_dependent: pointer _or_ array */
} va_list_struct;
...

void function2 (va_list_struct *myap);

void function1_v (va_list ap)
{
    va_list_struct myap;
    va_copy (myap.ap, ap);
    function2 (&myap);
    va_end (myap.ap);
}

void function1_f (int lastfixed, ...)
{
    va_list_struct myap;

    va_start (myap.ap, lastfixed);
    function2 (&myap);
    va_end (myap.ap);
}

void function2 (va_list_struct *myap)
{
    sometype x;

    x= va_arg (myap->ap, sometype);
}

Last edited by NevemTeve; 08-26-2014 at 10:17 AM.
 
Old 08-26-2014, 11:51 AM   #21
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
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.
 
Old 08-26-2014, 12:30 PM   #22
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
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.

Code:
/* va3264.c */

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

static void function2 (va_list ap);

static void function1 (va_list ap)
{
    int x;

    function2 (ap);
    x= va_arg (ap, int);
    printf ("function1: int arg=%d\n", x);

    function2 (ap);
    x= va_arg (ap, int);
    printf ("function1: int arg=%d\n", x);
}

static void function2 (va_list ap)
{
    int x;

    x= va_arg (ap, int);
    printf ("function2: int arg=%d\n", x);
}

void function_f (int lastfixed, ...)
{
    va_list ap;

    va_start (ap, lastfixed);
    function1 (ap);
    va_end (ap);
}

int main (void)
{
    function_f (9999, 1, 2, 3, 4, 5);

    return 0;
}
Results:
Code:
$ ./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
 
Old 08-26-2014, 05:28 PM   #23
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
Quote:
Originally Posted by NevemTeve View Post
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.
That's what va_copy is for.
 
1 members found this post helpful.
Old 08-26-2014, 11:59 PM   #24
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
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.

Last edited by NevemTeve; 08-27-2014 at 12:05 AM.
 
Old 08-27-2014, 07:20 AM   #25
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
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
 
Old 08-27-2014, 07:35 AM   #26
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
You didn't test this in 32-bit mode, did you?
Code:
$ ./mina32
f: 0: foo
g: 1: foo
f: 1: foo
f: 2: foo
g: 3: foo
f: 3: foo

$ ./mina64
f: 0: foo
g: 1: bar
f: 1: bar
f: 2: baz
g: 3: qux
f: 3: qux
 
1 members found this post helpful.
Old 08-27-2014, 07:52 AM   #27
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
Ah, now I see, thanks. That's interesting and disturbing at the same time.
 
Old 08-27-2014, 08:02 AM   #28
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
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:
Code:
typedef struct DKS {
    des_key_schedule dks;
} DKS;
void myfun (DKS *dks);
 
Old 11-22-2017, 10:12 AM   #29
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
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)

Code:
/* stdarg_test.c */

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

static void testfun (int nfun, ...)
{
    const char *fmt;
    va_list input_argptr;
    int i;

    va_start (input_argptr, nfun);
    for (i=0; i<nfun; ++i) {
        const char *funname= va_arg (input_argptr, const char *);

        if (strcmp (funname, "fputs")==0) {
            const char *msg= va_arg (input_argptr, const char *);
            fputs (msg, stdout);

        } else if (strcmp (funname, "sprintf")==0) {
            char buff [512];
#ifdef I_WANT_SEGFAULT_WITH_64BIT_LINUX
            va_list passed_argptr;

            fmt= va_arg (input_argptr, const char *);
            va_copy (passed_argptr, va_arg (input_argptr, va_list)); /* DOESN'T REALLY WORK */
            vsnprintf (buff, sizeof buff, fmt, passed_argptr);
#else
            void *passed_argptr;
            fmt= va_arg (input_argptr, void *);
            passed_argptr= va_arg (input_argptr, void *);
            vsnprintf (buff, sizeof buff, fmt, passed_argptr);
#endif
            fputs (buff, stdout);
        }
    }
}

static void middle (const char *fmt, ...)
{
    va_list passed_argptr;

    va_start (passed_argptr, fmt);
    testfun (3,
             "fputs", "start\n",
             "sprintf", fmt, passed_argptr,
             "fputs", "end\n"
             );
}

int main (int argc, const char **argv)
{
    middle ("argv[0]=%s argc=%d\n", argv[0], argc);
}
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Do I have a path problem, an Apache2 problem or a Javascript problem or any other pro rblampain Linux - Networking 0 12-29-2010 03:50 AM
Solved Problem Second GCC-Pass(or gettext sanity check problem) hoes Linux From Scratch 0 09-04-2005 10:20 AM
Sound Card problem(every time i install linux i have diffirent hardware problem) jacka1l Linux - Newbie 7 08-11-2005 06:10 AM
Lan configuration problem - NFS boot problem - RX&TX packets errors 242VDM242 Linux - Networking 4 11-25-2004 01:35 PM
perl problem? apache problem? cgi problem? WorldBuilder Linux - Software 1 09-17-2003 07:45 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:14 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration