#include <stdio.h>

/* eigener Testtyp (neben double und string s.u.) */
typedef struct {
char name[20];
int alter;
char geschlecht;
} Person;

/* Aktionen für jeden Typ */
void f_double(double*d) { printf("%f\n",*d); }
void f_string(char*d) { puts(d); }
void f_struct(Person*d) { printf("%s %d %c\n",d->name,d->alter,d->geschlecht); }

/* anonymer Stackelement-Typ */
typedef struct {
void (*f)();
void *d;
} Eintrag;

/* Aktionen für den Stack */
enum{PUSH,POP,PRINTALL};

/* unser Stack-Typ */
typedef struct{
Eintrag (*work)();
int i;
Eintrag eintrag[100];
} Stack;

#define CALL(x) x.f(x.d)
#define doublePUSH(s,p) s.work(&s,PUSH,p,f_double)
#define stringPUSH(s,p) s.work(&s,PUSH,p,f_string)
#define structPUSH(s,p) s.work(&s,PUSH,p,f_struct)
#define DOStack(s,e) s.work(&s,e)

/* alle Stackoperationen in einer Funktion zusammengefasst */
Eintrag work(Stack *this,int e,void*p,void(*f)())
{
  switch(e){
  case POP: return this->eintrag[--this->i];
  case PUSH: { Eintrag e={f,p}; this->eintrag[this->i++]=e;break; }
  case PRINTALL: { int i=this->i; while(i--) CALL(this->eintrag[i]);}
  }
}

int main()
{
  int i;
  Eintrag eintrag;

  /* Testdaten mit 3 unterschiedlichen Typen bereitstellen */
  double d[]={1,2,3};
  char *s[]={"s1","s2","s3"};
  Person p[]={{"schmidt",47,'m'},{"meier",11,'w'},{"lehmann",12,'m'}};

  /* unser Stack-Objekt */
  Stack stack={work};

  /* Testdaten mit ihren unterschiedlichen Typen in EINEN Stack packen (eigentliche Aufgabe) */
  for(i=0;i<3;++i)
    doublePUSH(stack,&d[i]),stringPUSH(stack,s[i]),structPUSH(stack,&p[i]);

  /* Kontrollausgabe: gesamter Stackinhalt */
  DOStack(stack,PRINTALL);

  /* Stack einzeln wieder abräumen und dabei jedes Element nochmal kontrollausgeben */
  for(i=0;i<9;++i)
    eintrag=DOStack(stack,POP),CALL(eintrag);

  return 0;
}
