N'est-il pas attendu que l'argument 1 (de test()) soit écrit dans le cadre de la pile de fonctions à une adresse basse ex : 0000 0004 (puisque 0000 0000 sera réservé pour l'adresse de retour) puis suivi de arg_a à une adresse plus élevée après le premier argument?
C'est ainsi que cela fonctionnait il y a longtemps, mais essentiellement tous les ABI pour les processeurs pleine taille (par opposition aux microcontrôleurs), définis depuis le milieu des années 1990, placent les premiers arguments dans des registres pour rendre les appels de fonctions plus rapides. Ils font cela que le callee soit variadic ou non. Vous ne pouvez pas accéder aux registres avec une arithmétique de pointeur, donc ce que vous essayez de faire est tout simplement impossible. En raison de ce changement, si vous regardez le contenu du stdarg.h
fourni par n'importe quel compilateur de génération actuelle, vous verrez que va_start
, va_arg
et va_end
sont définis à l'aide d'intrinsèques de compilateur, un peu comme
#define va_start(ap, last_named_arg) __builtin_va_start(ap, last_named_arg)
// etc
Vous avez peut-être été induit en erreur en pensant que les arguments étaient toujours placés sur la pile car la plupart des ABI x86 32 bits ont été définis à la fin des années 1980 (contemporains du 80386 et du 80486) et ils mettent effectivement tous les arguments sur la pile. La seule exception dont je me souvienne est Win32 "fastcall". Les ABI x86 64 bits, cependant, ont été définis au début des années 2000 (contemporains de l'AMD K8) et placent les arguments dans des registres.
Votre code ne fonctionnera pas de manière fiable même si vous le compilez pour du x86 32 bits (ou tout autre ancien ABI qui place tous les arguments sur la pile), car il enfreint les règles de la norme C concernant le décalage des pointeurs. Le pointeur arg_b
ne pointe pas vers "ce qui se trouve dans la mémoire à côté de a
", il ne pointe vers rien. (Formellement, il pointe un élément au-delà de la fin d'un tableau à un élément, car tous les objets non tableau sont traités comme le seul élément d'un tableau à un élément à des fins arithmétiques de pointeur. Vous êtes autorisé à effectuer l'arithmétique qui calcule ce pointeur, mais pas à le déréférencer.) Le déréférencement de arg_b
entraîne un comportement indéfini du programme, ce qui signifie que le compilateur est autorisé à le "mauvais compiler" arbitrairement.