[C] pass variabele arguments 2 keer

Pagina: 1
Acties:

  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
Ik dacht slim te zijn en dezelfde functie te implementeren voor allerlei soorten functies die heel veel op elkaar lijken. Het idee is het volgende:
Ik pass een functie-pointer en het aantal bijbehorende argumenten aan mijn functie, die dan als het aan een bepaalde criteria voldoet, deze functie aanroept met de goede argumenten. Ik heb momenteel dit:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// functie die aangeroepen zal worden:
static void *EnsureNoVehicleProcZ(Vehicle *v, uint16 tile, byte z)

/* VehicleFromPosProc is de definitie van de functietype, aangezien 
   er meerdere soorten zijn, met minder/meer argumenten
*/
typedef void *VehicleFromPosProc(Vehicle *v, ...);

// ik roep het aan via de volgende functie
VehicleFromPos(tile, (VehicleFromPosProc*)EnsureNoVehicleProcZ, tile, z)

// in VehicleFromPos doe ik dan het volgende:
void *VehicleFromPos(uint16 tile, VehicleFromPosProc *proc, ...) {
  va_list ap;
  ...
  va_start(ap, proc);
  if ((a = proc(v, ap)) != NULL)
    return a;
  va_end(ap);
  ...
}


Maar dit wil maar niet werken, ik krijg foute gegevens door. Wat doe ik fout, of is de hele opzet fout?

[ Voor 4% gewijzigd door Darkvater op 09-07-2004 13:36 ]


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge


  • EfBe
  • Registratie: Januari 2000
  • Niet online
erm... void pointer en dan a returnen?

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
EfBe schreef op 09 juli 2004 @ 13:58:
erm... void pointer en dan a returnen?
Erm, hoe bedoel je?
C:
1
if ((a = proc(v, (void *)ap)) != NULL)


??? Werkt evenzo niet.

Het gaat goed tot in VehicleFromPos. Want als ik daar
C:
1
2
va_arg(ap, uint16)
va_arg(ap, byte)

doe, krijg ik nog wel de goede waarden door. Alleen als ik dit dan weer doorgeef aan EnsureNoVehicleProcZ gaat het fout :'(

[ Voor 38% gewijzigd door Darkvater op 09-07-2004 16:46 ]


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge


Verwijderd

1) Waar komt je Vehicle* v vandaan? Die zit zo te zien niet in die va_list.

2) in het if-statement verlaat je de procedure (m.b.v. return) zonder eerst een va_end(ap) te doen, dat is een ontwerpfout.

3) waarom maak je niet gewoon een va_list van de 2e parameter van VehicleFromPosProc (en de onderliggende EnsureNoVehicleProcZ)?

[ Voor 26% gewijzigd door Verwijderd op 09-07-2004 16:49 ]


  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
Verwijderd schreef op 09 juli 2004 @ 16:45:
1) Waar komt je Vehicle* v vandaan? Die zit zo te zien niet in die va_list.

2) in het if-statement verlaat je de procedure (m.b.v. return) zonder eerst een va_end(ap) te doen, dat is een ontwerpfout.
Oh jah, dat is waar met die va_end(ap) :O . Die Vehicle *v komt daarvoor. Ik heb er nu dit van gemaakt:
C:
1
2
3
4
5
6
7
8
9
10
11
...
Vehicle *v = &_vehicles[veh];
void *a;
                
va_start(ap, proc);
a = proc(v, ap);
va_end(ap);

if (a != NULL)
  return a;
...


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge


Verwijderd

Met 3) bedoel ik dus zoiets:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static void *EnsureNoVehicleProcZ(Vehicle *v, va_list list) {
    uint16 tile= va_arg(list, uint16);
    byte z= va_arg(list, byte);
    ...
}

typedef void *(*VehicleFromPosProc)(Vehicle *, va_list);

void *VehicleFromPos(uint16 tile, VehicleFromPosProc proc, ...) {
    va_list ap;
    ...
    va_start(ap, proc);
    if ((a = proc(v, ap)) != NULL) {
      va_end(ap);
      return a;
    }
    ...
    va_end(ap);
    return NULL;
}

[ Voor 3% gewijzigd door Verwijderd op 09-07-2004 17:04 ]


  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
Verwijderd schreef op 09 juli 2004 @ 16:59:
Met 3) bedoel ik dus zoiets:

C:
1
2
3
4
5
6
7
static void *EnsureNoVehicleProcZ(Vehicle *v, va_list list) {
    uint16 tile= va_arg(list, uint16);
    byte z= va_arg(list, byte);
    ...
}

typedef void *VehicleFromPosProc(Vehicle *, va_list);
wow _/-\o_ . Ik wou net posten dat het niet werkt (ik had namelijk dit):
C:
1
2
3
4
5
6
static void *EnsureNoVehicleProcZ(Vehicle *v, va_list ap) {
  va_start(ap, v);
  tile = va_arg(ap, uint16);
  z = va_arg(ap, byte);
  va_end(ap);
}

Maar het is uiteraard logisch dat ik niet opnieuw moet beginnen en enden omdat dat in de aanroep al werd gedaan.

Aan de smilie kan je zien dat het gelukt is :D.

Nu rest mij nog maar 1 vraag: is het ook mogelijk zonder va_list in
C:
1
static void *EnsureNoVehicleProcZ(Vehicle *v, va_list ap)
, dus dat die gewoon
C:
1
static void *EnsureNoVehicleProcZ(Vehicle *v, uint16 tile, byte z)
blijft? Want nu is die functie zelf ook veranderd, wat ik eigenlijk niet wilde.

[ Voor 15% gewijzigd door Darkvater op 09-07-2004 17:05 ]


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge


Verwijderd

Darkvater schreef op 09 juli 2004 @ 17:04:
Nu rest mij nog maar 1 vraag: is het ook mogelijk zonder va_list in
C:
1
static void *EnsureNoVehicleProcZ(Vehicle *v, va_list ap)
, dus dat die gewoon
C:
1
static void *EnsureNoVehicleProcZ(Vehicle *v, uint16 tile, byte z)
blijft? Want nu is die functie zelf ook veranderd, wat ik eigenlijk niet wilde.
Nee, niet op deze manier. Je zou dan een stub-functie moeten schrijven die alle va_args van de va_list haalt en vervolgens EnsureNoVehicleProcZ aanroept, dus zoiets:

C:
1
2
3
4
5
static void *EnsureNoVehicleProcZstub(Vehicle *v, va_list list) {
    uint16 tile= va_arg(list, uint16);
    byte z= va_arg(list, byte);
    return EnsureNoVehicleProcZ(v, tile, z);
}


Maar ik denk persoonlijk dat dit meer werk oplevert dan de procedure zelf aanpassen (indien dat kan).

  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
Verwijderd schreef op 09 juli 2004 @ 17:11:
Nee, niet op deze manier. Je zou dan een stub-functie moeten schrijven die alle va_args van de va_list haalt en vervolgens EnsureNoVehicleProcZ aanroept, dus zoiets:

C:
1
2
3
4
5
static void *EnsureNoVehicleProcZstub(Vehicle *v, va_list list) {
    uint16 tile= va_arg(list, uint16);
    byte z= va_arg(list, byte);
    return EnsureNoVehicleProcZ(v, tile, z);
}


Maar ik denk persoonlijk dat dit meer werk oplevert dan de procedure zelf aanpassen (indien dat kan).
Uiteraard. Dat ik daar niet aan dacht 8)7 . Ik zal kijken of dat wel haalbaar of slim is, aangezien je dan toch wat van de voordelen kwijt bent die ik wou behalen. Iig zeer bedankt voor de goede hulp _/-\o_ _/-\o_


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Darkvater schreef op 09 juli 2004 @ 16:27:
[...]


Erm, hoe bedoel je?
C:
1
if ((a = proc(v, (void *)ap)) != NULL)


??? Werkt evenzo niet.
Nee, je returnt een waarde maar de functie is void gedefinieerd, dat vond ik raar :)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Wat je wil kan niet; als je een functie met parameterlijst (X,Y,Z) wil aanroepen, dan moet je dat via een function pointer doen met type (*)(X,Y,Z). Het type (*)(X, ... ) is niet geschikt, ook al kun je aan beiden argumenten (x,y,z) meegeven.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
MSalters schreef op 09 juli 2004 @ 19:24:
Wat je wil kan niet; als je een functie met parameterlijst (X,Y,Z) wil aanroepen, dan moet je dat via een function pointer doen met type (*)(X,Y,Z). Het type (*)(X, ... ) is niet geschikt, ook al kun je aan beiden argumenten (x,y,z) meegeven.
Ya, zoiets kwam ik ook wel achter omdat ie het niet wou. In ieder geval doet ie het met de va_list, en dat is al een stap voorwaarts :)


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Als zeurende sidenote: voor dit soort dingen is C++ nu juist erg geschikt. Ik zie dat je niet echt aan de linux kernel programmeert gezien de method/parameter names, dus wellicht een optie om eens over na te denken, het zou je code een stuk vereenvoudigen.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
EfBe schreef op 10 juli 2004 @ 11:16:
Als zeurende sidenote: voor dit soort dingen is C++ nu juist erg geschikt. Ik zie dat je niet echt aan de linux kernel programmeert gezien de method/parameter names, dus wellicht een optie om eens over na te denken, het zou je code een stuk vereenvoudigen.
:D Het is een spel genaamd OpenTTD, een open source spinoff van TTDLX die werkt op Windows, Linux, MacOS, Symbian, Sun, etc. etc. Het probleem is dat alles in C is geschreven, dus eventjes overstappen op C++ zit er niet bij...tenminste voorlopig :)


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge

Pagina: 1