Variadiques
Dans la premiere version d’UNIX les variadiques etaient gerees en assumant la location des arguments en memoire d’un PDP9.
La maniere portable et standart est d’utiliser une ellipse.
Macros variadiques aussiS
Dans unix, on utile un pointeur sur le premier argument et on le fait croitre
https://www.tuhs.org/cgi-bin/utree.pl?file=V3/c/c03.c 🌍⤴
Voici printf sur UNIX v3
printn(n,b) {
extern putchar;
auto a;
if(a=n/b) /* assignment, not test for equality */
printn(a, b); /* recursive */
putchar(n%b + '0');
}
printf(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9)
char fmt[]; {
extern printn, putchar, namsiz, ncpw;
char s[];
auto adx[], x, c, i[];
adx = &x1; /* argument pointer */
loop:
while((c = *fmt++) != '%') {
if(c == '\0')
return;
putchar(c);
}
x = *adx++;
switch (c = *fmt++) {
case 'd': /* decimal */
case 'o': /* octal */
if(x < 0) {
x = -x;
if(x<0) { /* - infinity */
if(c=='o')
printf("100000");
else
printf("-32767");
goto loop;
}
putchar('-');
}
printn(x, c=='o'?8:10);
goto loop;
case 's': /* string */
s = x;
while(c = *s++)
putchar(c);
goto loop;
case 'p':
s = x;
putchar('_');
c = namsiz;
while(c--)
if (*s)
putchar((*s++)&0177);
goto loop;
}
putchar('%');
fmt--;
adx--;
goto loop;
}
Naviguer entre variadiques consiste à faire de l’arithmétique de pointeurs.
Incompatibilité
A noter qu’une variadique ancienne et une variadique avec la sysntaxe
nouvelle void foo(int, ...), ne sont pas compatibles et ne sont
pas tenues d’obeir aux memes conventions d’appel.
De la sorte la fonction int func(int arg0, double arg1);
n’est pas tenu d’avoir la meme convention d’appel, d’usage
des registres, etc. que la fonction int func2().
De la même façon int func3(...); (depuis le C23) ou
int func4(int arg0, ...); peuvent avoir une ABI différentes
des deux premières fonctions.
Pour résumer
int func1(int arg0, double arg1);
int func2(); // interdit depuis le C23
int func3(...); // interdit avant le C23
int func4(int arg0, ...);
int a = 0;
double b = 1;
func1(a, b);
func2(a, b);
func3(a, b);
func4(a, b);
// ces 4 appels de fonction peuvent tous générer
// un code binaire différent
int(ptr*)() = func2;
ptr(2, 1.5); // ok
ptr = func1;
ptr(2, 1.5); // /!\ comportement indéterminé