1

Probleme:
Comment en C standard (C99) "simuler" le comportement des fonctions avec argument par defaut du C++ ?

int f(int x=2, int y=3, int z=4, int t=5);

?

2

En faisant une fonction pour chaque nombre de paramètres ?

int f() {return f(2, 3, 4, 5);}
int f(int x) {return f(x, 3, 4, 5);}
int f(int x, int y) {return f(x, y, 4, 5);}
....
int f(int x, int y, int z, int t);

3

const int val_x = 2;
const int val_y = 3;
const int val_z = 5;
const int val_t = 5;

int f(int,int,int,int);

main(blabla)
{
// les trucs qui vont bien

int f(val_x,val_y,val_z,val_t);

// les trucs qui vont bien
}

4

spectras :
En faisant une fonction pour chaque nombre de paramètres ?

int f() {return f(2, 3, 4, 5);}
int f(int x) {return f(x, 3, 4, 5);}
int f(int x, int y) {return f(x, y, 4, 5);}
....
int f(int x, int y, int z, int t);
Le C99 autorise la surcharge de fonctions ?
Terrible, je ne savais pas top
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

5

Hmmm non j'ai posté un peu vite en fait ^^
T'es obligé de les suffixer par exemple f0 f1 f2 f3

6

La seule solution que je vois est d'utiliser args.h sad
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

7

Hmm, je crois que je vois une solution, mais elle ne marche que si les arguments fournis sont tels que "-argument == -(argument)" sad

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

8

On peut toujours passer par le preprocesseur, mais bon :/ (Et puis je suppose que vous voulez une solution C only:P)

9

Ben je vois pas trop comment le préprocesseur peut être utile sur un coup comme ça en fait ?

10

j'essaye de faire mieux, parce que là, on ne peut pas passer MAGIC comme paramètre...

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

#define MAGIC 424242

void f1(int plop,...){
  int args[3] = {42,51,1664}; /* default values */
  va_list ap;
  va_start(ap, plop);
  for(int i = 0;i < 3;i++){
    int tmp = va_arg(ap,int);
    if(tmp == MAGIC)
       break;
    else
      args[i] = tmp;
  }
  va_end(ap);
  for(int i = 0;i < 3;i++){
    printf("%d ",args[i]);
  }
  printf("\n");
}

#define f(...) f1(42, ##__VA_ARGS__ , MAGIC )

int main(int argc, char *argv[]) {
 f(1);
 f(1,2);
 f(1,2,3);
}

avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

11

voilà, à noter que je n'arrive pas à faire marcher f();

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

void f1(int plop,...){
  int args[3] = {50,51,52};
  int rd_args[7];
  int nb_rd_args = 0;

  va_list ap;
  va_start(ap, plop);
  for(int i = 0;i < 7;i++){
    rd_args[i] = va_arg(ap,int);
    if(i > 3
       && rd_args[i] == 0
       && rd_args[i-1] == 42
       && rd_args[i-2] == 42
       && rd_args[i-3] == 42) {
      nb_rd_args = i - 3;
      break;
    }
  }
  va_end(ap);
  for(int i = 0;i < nb_rd_args;i++)
    args[i] = rd_args[i];
  for(int i = 0;i < 3;i++){
    printf("%d ",args[i]);
  }
  printf("\n");
}

#define f(...) f1(42 , ##__VA_ARGS__ , 42, 42, 42, 0)

int main(int argc, char *argv[]) {
 f(10);
 f(10,11);
 f(10,11,12);
}

avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

12

C'est normal, ce n'est pas possible sans une extension spécifique.
Par exemple, gcc dispose d'un équivalent à __VA_ARGS__ qui fait un cas particulier : s'il n'y a pas d'arguments et que le token précédent le __Va_ARGS__ est une virgule, il le supprime.

13

nope c'est pas GCC, c'est du c99, il faut mettre ##__VA_ARGS__ mais ça ne marche pas si les seuls arguments de la macro sont ceux de l'ellipse, il faut un premier argument pour que ça fonctionne.
#define f(1,...) g(1, ##__VA_ARGS__)
marche, mais pas
#define f(...) g(1, ##__VA_ARGS__)
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

14

(et oui, gcc a cette "extension" depuis bien longtemps avec les args... et consorts
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

15

oui, mais justement, je disais que gcc a une extension qui se met à la place de __VA_ARGS__ qui lui permet de marcher avec aucun argument.
vala =>
This is a special feature of the GNU C preprocessor: `##' before a rest argument that is empty discards the preceding sequence of non-whitespace characters from the macro definition.

16

certes, certes, mais dans le ./1, y'a marqué en C99 standard tongue
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

17

f (stderr, format , ## args)
Et à l'usage ça ressemble à ça 	

#define eprintf(format, args...)  \
 fprint

note l'espace entre format et la virgule qui suit (sinon format sera dégagé en même temps que la virgule), ansi que l'espace entre ## et args (sinon ça serait pris comme de la concaténation de tokens)

18

./16> j'ai pas dit le contraire, c'est pour ça que je l'avais pas proposé hein smile
je commentais juste sur "voilà, à noter que je n'arrive pas à faire marcher f(); "

19

BookeldOr :
nope c'est pas GCC, c'est du c99, il faut mettre ##__VA_ARGS__ mais ça ne marche pas si les seuls arguments de la macro sont ceux de l'ellipse, il faut un premier argument pour que ça fonctionne.

J'ai jeté un rapide coup d'oeil à la norme, et j'ai pas trouvé où ils auraient pu parler de ça confus

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

20

spectras :
f (stderr, format , ## args)
Et à l'usage ça ressemble à ça 	

#define eprintf(format, args...)  \
 fprint

note l'espace entre format et la virgule qui suit (sinon format sera dégagé en même temps que la virgule), ansi que l'espace entre ## et args (sinon ça serait pris comme de la concaténation de tokens)

Alors ça le coup du whitespace c'est juste pour être compatible avec les vieux GCC, ça n'a aucune influence sur les plus récents : ils zappent simplement la virgule si c'est le dernier token ^^ (et sinon émettent un warning)
Quant à l'espace entre ## et args, tu es sûr que ça a une quelconque influence ? hum

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

21

./20> oui, je m'en suis douté en écrivant, vu que j'ai peché ça dans la doc de gcc 2 (qui est la première à être remontée au google), et déjà dedans ils précisaient qu'il était fort possible qu'ils suppriment au token par token, ce qui est plus propre. smile

22

(et mon edit ?)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

23

Ton edit, c'est une bonne question. Ca dépend ptet aussi de la version de gcc. Parce que même si théoriquement le ##truc sert à concaténer les tokens, concaténer à une virgule ça sert à rien donc c'est facile de faire le cas particulier, et de ne pas dépendre de l'espace.

24

Oui, de toute façon "## truc" a exactement la même signification que "##truc", donc je vois pas pourquoi ils accepteraient l'un et pas l'autre...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

25

alors, PpHd, la soluce? tongue
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

26

./10: Cette solution ne marche pas si on a des types differents.

Je rappelle la macro suivante (qui n'est pas de moi) :

Macro calcul du nombre d'arguments d'un appel de macro
#define PP_NARG( ...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define PP_RSEQ_N() 9,8,7,6,5,4,3,2,1,0


Avec les résultats :
PP_NARG(A) -> 1
PP_NARG(A,B) -> 2
PP_NARG(A,B,C) -> 3
PP_NARG(A,B,C,D) -> 4
PP_NARG(A,B,C,D,E) -> 5



A partir de la, on peut tirer :

int f(int, int, int, int);

#define f(...) select_4(__VA_ARGS__, f(__VA_ARGS__),f(__VA_ARGS__,5),f(__VA_ARGS__,4,5),f(__VA_ARGS__,3,4,5),f(2,3,4,5))
#define select_4(_1,_2,_3,_4,N,...) N


Note : je l'ai refaite de tete. Je peux donc me tromper.

Et donc
 int (*func) (int, int, int, int);
 func = f;
 f (17,42);
 f(17);

sera préprocessé en :
 int (*func) (int, int, int, int);
 func = f;
 f (17,42,4,5);
 f(17,3,4,5);


A noter qu'il n'y a pas les "drawback" classiques des macros vu que tout est simplifié pendant l'étape de préprocessing ! La vérification du typage des fonctions restent faites, et on peut meme affecter un ptr de fonction !
Par contre:
 f();

marche pas (sans extention GNU). Dommage.

Mais pas mal quand meme, non ?

Surtout que c'est un poil plus flexible que le C++ :
f(x) est transformable en f(x,x)
Je vous laisse mediter. Si vous faites marcher f(); tout en restant standard, je suis prenneur.

27

D'accord, moi je croyais que tu avais une méthode qui marchait même avec aucun argument. C'est nettement plus difficile, puisqu'il faut transformer la chaîne vide en la valeur par défaut, et laisser les autres expressions inchangée...

On peut qd même transformer f() en f(0), à condition que le dernier paramètre soit un int ou un pointeur :
#define new_f(...) old_f(__VA_ARGS__+0)
(enfin je suis pas sûr à 100% que ça marche toujours : par exemple +0 peut transformer un char en int, du coup ça peut changer des choses (sizeof(x+0)!=sizeof(x)), mais d'un autre côté étant donné qu'il n'y a aucune parenthèse entourant le +0 et qu'il est le plus à droite dans l'expression, je ne sais pas si ce changement peut effectivement avoir un impact confus)
Mais j'ai pas trouvé de moyen de faire une astuce du genre avec d'autres valeurs que 0, pas sûr que ça soit possible sad



Enfin sinon il y a une autre méthode qui m'a l'air correcte, mais qui a l'inconvénient d'imposer un certain overhead en taille et en vitesse si le compilo n'est pas assez malin :
#define new_f(...) new_f2((__VA_ARGS__))
#define new_f2(parms) (#parms[2] ? ...valeur par défaut... : old_f parms)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)