You are not logged in.

#1 2007-03-20 21:40:18

ezzetabi
Member
Registered: 2006-08-27
Posts: 947

Dynamically create a va_list? C

Language C, GNU 99.
I have the 'prompt' problem, I have a format string (like '[\u@\h \W]\$') and I have to replace all the occurrences of special character sequences with its relative value.
A compile time I do not know what, how many sequences I'll have so I can't just use sscanf.
My idea was parsing the string, when I meet special sequence characters I replace them with the scanf conversion sequence and I pack somewhere the value. In the example '[\u@\h \W]\$' would become '[%s@%s %s]\$' while I pack somewhere "ezzetabi", "computer", "~"...

Finally calls vsscanf(). I know there is no portable C solution, so I am asking for a Linux wide solution.

How is va_list behind? How can I create it on the fly?
Other solutions different than remaking vsscanf?

Thanks everyone.

Offline

#2 2007-03-21 17:52:32

bboozzoo
Member
From: Poland
Registered: 2006-08-01
Posts: 125

Re: Dynamically create a va_list? C

I'm not quite sure if this can be achieved. You might try looking into gcc internals to see how they hande variable arguments list, though you may end up parsing the string anyway.

This gives some insight into va_list stuff, although it's open watcom specific
http://www.koders.com/c/fidD3D96BF58339 … 4DD9F.aspx

Last edited by bboozzoo (2007-03-21 17:53:23)

Offline

#3 2007-03-26 17:32:38

ezzetabi
Member
Registered: 2006-08-27
Posts: 947

Re: Dynamically create a va_list? C

Solution:
the va_list is a pointer to an area memory with the needed values packed in order as in a struct.

e.g.

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

int main() {
  char* m = (char*) malloc(sizeof(int)*2 + sizeof(char*)); /* prepare enough memory*/
  void* bm = m; /* copies the pointer */
  char* string = "I am a string!!"; /* an example string */

  (*(int*)m) = 10; /*puts the first value */
  m += sizeof(int); /* move forward the pointer to the next element */

  (*(char**)m) = string; /* puts the next value */
  m += sizeof(char*); /* move forward again*/

  (*(int*)m) = 20; /* puts the third element */
  m += sizeof(int); /* unneeded, but here for clarity. */

  vprintf("%d %s %d\n", bm); /* the deep magic starts here...*/
  free(bm);
}

and it outputs "10 I am a string!! 20\n"

And since it is impossible kernel.org decides to change how functions pass parameters (it would mean that every program need to be recompiled...) it should be safe and *linux* portable.

Last edited by ezzetabi (2007-03-26 17:37:52)

Offline

#4 2007-03-26 19:46:32

bboozzoo
Member
From: Poland
Registered: 2006-08-01
Posts: 125

Re: Dynamically create a va_list? C

ezzetabi wrote:

Solution:
the va_list is a pointer to an area memory with the needed values packed in order as in a struct.

e.g.

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

int main() {
  char* m = (char*) malloc(sizeof(int)*2 + sizeof(char*)); /* prepare enough memory*/
  void* bm = m; /* copies the pointer */
  char* string = "I am a string!!"; /* an example string */

  (*(int*)m) = 10; /*puts the first value */
  m += sizeof(int); /* move forward the pointer to the next element */

  (*(char**)m) = string; /* puts the next value */
  m += sizeof(char*); /* move forward again*/

  (*(int*)m) = 20; /* puts the third element */
  m += sizeof(int); /* unneeded, but here for clarity. */

  vprintf("%d %s %d\n", bm); /* the deep magic starts here...*/
  free(bm);
}

and it outputs "10 I am a string!! 20\n"

And since it is impossible kernel.org decides to change how functions pass parameters (it would mean that every program need to be recompiled...) it should be safe and *linux* portable.

This is just fine as long as the size of each element is equal to word size (4 bytes). Check out this example:

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

int main() {
  char* m = (char*) malloc(sizeof(int)*2 + sizeof(char*) + sizeof(char)*2);
  void* bm = m; /* copies the pointer */
  char* string = "I am a string!!"; /* an example string */

  (*(int*)m) = 10; /*puts the first value */
  m += sizeof(int); /* move forward the pointer to the next element */

  (*(char**)m) = string; /* puts the next value */
  m += sizeof(char*); /* move forward again*/

  (*(int*)m) = 20; /* puts the third element */
  m += sizeof(int); /* unneeded, but here for clarity. */

  (*(char*)m) = 0x32; /* 2 in ascii */
  m += sizeof(char);

  (*(char*)m) = 0x33; /* 3 in ascii */

  vprintf("%d %s %d %d %d\n", bm); /* this fails, neighbouring chars interpreted as one int */
  vprintf("%d %s %d %c %c\n", bm); /* this too, unaligned with respect to word */
  free(bm);
}

as both chars are unaligned with resect to word the output will be:
10 I am a string!! 20 13106 0
10 I am a string!! 20 2  /* here is not displayer missing 0x0 character */
and on big endian machine you migh expect something like (though I don't have any big endian machine, perhaps someone can verify it?)
10 I am a string!! 20 842203136 0
10 I am a string!! 20 /* both 0x0? */

Offline

#5 2007-03-26 20:13:10

ezzetabi
Member
Registered: 2006-08-27
Posts: 947

Re: Dynamically create a va_list? C

Nice catch, this probably avoided some future tiring bug seeking season.

So I have to find the smallest multiple of sizeof(int) greater or equal of sizeof(T) (where T is a type) and use it as T size in those calculations.

Last question, an int is always long as a machine word?

Offline

#6 2007-03-26 21:08:00

bboozzoo
Member
From: Poland
Registered: 2006-08-01
Posts: 125

Re: Dynamically create a va_list? C

not necessarily, take a look at bits/wordsize.h and stdint.h

Offline

Board footer

Powered by FluxBB