Newsgroup: it.comp.lang.c
Titolo: Varargs e funzioni varargs "passanti"

Per motivi che non sto qui a spiegarvi per il poco tempo
ho la necessita' di scrivere funzioni a numero di argomenti variabili
che poi a loro volta passano gli stessi parametri a funzioni con
parametri analoghi. Le funzioni "passanti" a volte hanno bisogno
di gestire (leggere non modificare) i parametri passati.
Non capisco il motivo per cui in diretta:
   main -> funzione
va tutto bene, mentre se uso:
   main -> funzione_passante -> funzione 
si perde dal 2' all'ennesimo parametro.
qualcuno mi sa indicare cosa sbaglio ?? sto usando gcc sotto linux intel.
Se la soluzione non e' ansi ma legata al gcc mi va bene lo stesso :-).
Posto qui sotto un prg d'esempio.
Un grazie a chiunque ci buttera' anche solo un occhio.
Matteo.
--------- 8< --------- 8< --------- 8< --------- 8< --------- 8< ---------
#include <stdio.h>
#include <varargs.h>
int vfun(pippo,va_alist)
int pippo;
va_dcl
{
   va_list ap;
   char *uno;
   long due;
 
   va_start(ap);
   uno = va_arg(ap, char *);
   due = va_arg(ap, long);
   va_end(ap);
 
   fprintf(stderr,"Check vfun %d %s %ld\n",pippo,uno,due);
   return 1;
   }
int vfun2(pippo,va_alist)
int pippo;
va_dcl
{
   fprintf(stderr,"Check vfun2\n");
   vfun(pippo,va_alist);
   return 1;
}
main()
{
   char *p = "STRINGA";
   long l = 1000000000L;
   fprintf(stderr,"Good\n");
   vfun(10,p,l);
   fprintf(stderr,"Wrong\n");
   vfun2(10,p,l);
   exit(0);
   }
/* END */

 va_dcl
Non solo i tuoi headers, ma anche le tue procedure sono pre-ANSI :-)
Inoltre il valore ritornato dalle vfun non viene mai utilizzato, il
che fa pensare che tu non conosca la keyword 'void'.
Ma bando alle ciance: tu vuoi in sostanza dichiarare due funzioni
variadiche, delle quali una richiami l'altra (se ho capito bene; non
sono sicuro).
In sostanza in ANSI C questo non e' possibile; si possono usare dei
trucchi, che pero' non e' garantito che funzionino.  Con gcc 2.95.2 si
puo' fare cosi':
</begin code>
#include <stdio.h>
#include <stdarg.h>
void vfun(int, va_list);                /* Prototipi */
void vfun2(int, ...);
void vfun(int pippo, va_list vl) {
  char *uno = va_arg(vl, char *);
  long  due = va_arg(vl, long);
  printf("Inside vfun: pippo = %d; char[] =\"%s\"; long = %ld\n",
         pippo, uno, due);
}
void vfun2(int pippo, ...) {
  va_list vl;
  char *uno;
  long  due;
  printf("Inside vfun2, called with pippo = %d\n", pippo);
  va_start(vl, pippo);
  puts("Calling vfun");
  vfun(pippo, vl);
  puts("Back from vfun");
  uno = va_arg(vl, char *);
  due = va_arg(vl, long);
  printf("char[] =\"%s\"; long = %ld\n", uno, due);
  va_end(vl);
}
int main() {
  char *p = "STRINGA";
  long  l = 1000000000L;
  puts("Calling vfun2");
  vfun2(10,p,l);
  return 0;
}
</end code>
Infatti:
MLO@mlinux 49 $ gcc -ansi -pedantic -Wall -o foo foo.c
MLO@mlinux 50 $ ./foo
Calling vfun2
Inside vfun2, called with pippo = 10
Calling vfun
Inside vfun: pippo = 10; char[] ="STRINGA"; long = 1000000000
Back from vfun
char[] ="STRINGA"; long = 1000000000
MLO@mlinux 51 $
Il trucco sta nel chiamare va_start e va_end in una sola funzione, e
nell'utilizzare la va_list ottenuta due volte.  Bada bene che il tutto
NON E' PORTABILE: le va_procedures in genere sono implementate come
macro, e con determinati compilatori e/o ambienti operativi richiamare
una di esse puo significare alterare le cose nei parametri di chiamata
in maniera non reversibile.
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it

 
non posso perche' la funzione piu' interna e' una ioctl, alla quale
non piacciono molto le va_list come argomenti.
[snip]
il metodo che hai utilizzato tu e' analogo a quello della vprintf ma
nel mio caso non e' applicabile :-(
Ma e' possibile che non ci sia un metodo (possibilmente semplice)
sotto gcc per risolvere questi problemi (pre o post ansi che sia) ??
from stdarg man page:
--- >8 --- >8 --- >8 --- >8 --- >8 --- >8 --- >8 --- >8 --- >8 --- 
BUGS
       Unlike the varargs macros, the stdarg macros do not permit
       programmers  to  code  a function with no fixed arguments.
       This problem generates work mainly when converting varargs
       code  to stdarg code, but it also creates difficulties for
       variadic functions that wish to pass all  of  their  argu­
       ments on to a function that takes a va_list argument, such
       as vfprintf(3).
--- >8 --- >8 --- >8 --- >8 --- >8 --- >8 --- >8 --- >8 --- >8 --- 
non trovi che sia un bug della varargs sotto gcc questo malfunzionamento ??
Grazie del tuo tempo.
Matteo.

 quale non piacciono molto le va_list come argomenti.
  La ioctl(), pero`, non accetta un numero variabile di argomenti,
bensi` un argomento di tipo variabile. Non sarebbe meglio, a questo
punto, utilizzare il polimorfismo fornito dal puntatore a void oppure
dai record varianti?
	Alla prossima,
		Marco

 Scusa ma e' falso 
  Dipende dalla piattaforma e dal parametro /request/. Per maggiori
informazioni:
	$ man ioctl_list
  Probabilmente, potrebbe essere la soluzione per il tuo problema.
Altrimenti, e` un problema senza soluzione, se affrontato con il tipo di
implementazione che hai in mente. ;)
       Alla prossima,
               Marco



Sotto linux ioctl *ha 3* argomenti. Poiche' spesso il terzo puo' essere
ignorato a volte si omette. Forse e da ricollegarsi al fatto che
inizialmente il C non effettuava controlli sui parametri.
Comunque la dichiarazione e':
int ioctl(int d, int request, ...);
Ma questo non significa che esistono ioctl con piu' di tre argomenti.
Per sicurezza guardate qua' la definizione della ioctl nel kernel di linux
( tratta dal file linux/fs/ioctl.c )
asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, 
			 unsigned long arg);
Partendo da questo presupposto ( massimo TRE argomenti ) si puo' fare una
cosa del tipo:
int miaioctl( int p1, ... ){
	unsigned long	pp1,pp2,pp3;
	va_list pp;
	va_start( pp,p1 );
	pp1=p1; // o qualunque altro cosa 
	pp2=va_arg( pp, unsigned long );
	pp2=va_arg( pp, unsigned long );
	va_end( pp );
	return ioctl( pp1,pp2,pp3 );
}
Conoscendo a priori il numero massimo di parametri ( = 3 ) la cosa e'
semplice; al limite se le possibilita' sono poche si puo' creare uno switch
su il parametro noto e in funzione di esso stabilire se bisogna chiamare una
ioctl con due o tre parametri, ma non vedo vantaggi rispetto alla soluzione
che propongo.