[C]Pointers naar functies, recursief

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • CAPSLOCK2000
  • Registratie: Februari 2003
  • Laatst online: 11-09 21:28

CAPSLOCK2000

zie teletekst pagina 888

Topicstarter
Het volgende probleem is voornamelijk een kwestie van "hoe schrijf ik het netjes op". Ik heb werkende code, alleen geen erg mooie. Ik hoop dat jullie een netter alternatief weten.

Ik heb twee functies, funcA en funcB, die beurtelings elkaar aanroepen.

Van zowel funcA als funcB zijn er meerdere varianten, die allemaal met elkaar gecombineerd kunnen worden. Vooraf is niet bekend welke combinatie gebruikt zal worden. Daarom geef ik de functies mee als argumenten.

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int funcA(int arg1, int (*functieA)(), int (*functieB)()) {
  iets;
  functieB(arg1, functieA, functieB);
  nog iets;
}

int funcB(int arg1, int (*functieA)(), int (*functieB)()) {
  doe iets;
  functieA(arg1, functieA, functieB);
  doe meer;
}

void main(int argc, char **argv)
{
  funcA(0, funcA, funcB);
}


Mijn probleem is dat ik geen volledige types kan opgeven voor deze functies. Ze krijgen hun eigen definitie immers mee als argument, waardoor je in een circulaire zou definitie komen. Daarom heb ik, zoals je hierboven kan zien, de functies maar (impliciet) als void gedeclareerd. C is dom genoeg om het gewoon te slikken.

Allemaal mooi en prachtig, tot je een fout maakt. De compiler kan niet controleren hoeveel argumenten er nodig zijn, en doet dit ook niet. functieA en functieB kun je dus met zoveel (of weinig) argumenten aanroepen als je wil, de compiler vindt het allemaal prima. Werken doet het dan uiteraard niet.

Ik heb allerei pogingen gedaan om met structs en typedefs, maar heb niks kunnen bedenken.

PS1. Bijkomende wes is dat het in C90 werkt. Het project waar ik me op baseer is puur C90, en dat wil ik liever zou houden. Als je een heel elegante oplossing weet voor een andere C versie wil ik er nog wel naar kijken, maar C++ is geen optie.

PS2. De werkelijkheid is complexer, en er worden nog een hoop andere argumenten meegegeven.
Uit oogpunt van de leesbaarheid heb ik die in een struct geduwd. Ik zou het dus helemaal niet erg vinden als jouw oplossing ook een struct gebruikt. Hieronder de code met de struct en wat typdefs.

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* dit werkt niet:
typedef int (*mijnFunctie)(int arg1, Settngs settings);
*/


/* dit wel: */
typedef int (*mijnFunctie)();

typedef struct Settings {
  mijnFunctie functieA;
  mijnFunctie functieB;
  int arg3;
} Settings;


int funcA(int arg1, Settings settings) {
  iets;
  settings.functieB(arg1, settings);
  nog iets;
}

int funcB(int arg1, Settings settings) {
  weer iets;
  settings.functieA(arg1, settings);
  nog meer iets;
}

int main(int argc, char **argv)
{
  Setting settings;
  settings.functieA = funcA;
  settings.functieB = funcB;

  funcA(0, settings);
}

[ Voor 4% gewijzigd door CAPSLOCK2000 op 18-08-2009 19:31 . Reden: Conflicterende functienamen en argumenten hernoemd. ]

This post is warranted for the full amount you paid me for it.


Acties:
  • 0 Henk 'm!

  • bobo1on1
  • Registratie: Juli 2001
  • Laatst online: 18-05 17:57
CAPSLOCK2000 schreef op dinsdag 18 augustus 2009 @ 18:03:
Daarom heb ik, zoals je hierboven kan zien, de functies maar (impliciet) als void gedeclareerd. C is dom genoeg om het gewoon te slikken.
Dat zie ik eerlijk gezegd niet terug.
Overigens lijkt het me een vrij slecht idee om functiepointers te gebruiken met dezelfde naam als de functies waar ze naar wijzen.

Maar eh, dit kun je toch gewoon gebruiken:

C:
1
2
3
4
void test(int (*p_test)(int, int, int))
{
  p_test(1, 2, 3);
}


Doet volgens mij wel wat je wil.

Impedance, a measure of opposition to time-varying electric current in an electric circuit.
Not to be confused with impotence.


Acties:
  • 0 Henk 'm!

  • CAPSLOCK2000
  • Registratie: Februari 2003
  • Laatst online: 11-09 21:28

CAPSLOCK2000

zie teletekst pagina 888

Topicstarter
bobo1on1 schreef op dinsdag 18 augustus 2009 @ 18:35:
[...]


Dat zie ik eerlijk gezegd niet terug.
C:
1
int (*functieA)()

Deze functie is gedefinieerd zonder argumenten. Hij heeft ze wel, dat is nogal vies, vandaar mijn vraag.
Overigens lijkt het me een vrij slecht idee om functiepointers te gebruiken met dezelfde naam als de functies waar ze naar wijzen.
klopt, dat was minder handig in mijn voorbeeld, ik ga het aanpassen.
Maar eh, dit kun je toch gewoon gebruiken:

C:
1
2
3
4
void test(int (*p_test)(int, int, int))
{
  p_test(1, 2, 3);
}


Doet volgens mij wel wat je wil.
Ik wil aan de functie p_test ook weer een functie-pointer meegeven als argument.

This post is warranted for the full amount you paid me for it.


Acties:
  • 0 Henk 'm!

  • bobo1on1
  • Registratie: Juli 2001
  • Laatst online: 18-05 17:57
Dit misschien dan:

C:
1
2
3
4
5
6
7
8
9
10
11
int functieA(int arg1, int (*p_functieA)(int, int(*)(), int(*)()), int (*p_functieB)(int, int(*)(), int(*)()))
{
  p_functieB(arg1, p_functieA, p_functieB);
  return 0;
}

int functieB(int arg1, int (*p_functieA)(int, int(*)(), int(*)()), int (*p_functieB)(int, int(*)(), int(*)()))
{
  p_functieA(arg1, p_functieA, p_functieB);
  return 0;
}


Die controleert of je genoeg argumenten aan de functiepointer meegeeft, alleen niet of de functiepointers dit je als argument meegeeft ook het juiste aantal argumenten moeten hebben.

Impedance, a measure of opposition to time-varying electric current in an electric circuit.
Not to be confused with impotence.


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22:02
CAPSLOCK2000 schreef op dinsdag 18 augustus 2009 @ 19:27:
C:
1
int (*functieA)()

Deze functie is gedefinieerd zonder argumenten. Hij heeft ze wel, dat is nogal vies, vandaar mijn vraag.
Deze functie is gedefinieerd met een variabel aantal argumenten, niet zonder argumenten.

Als ik het goed begrijp wil je @runtime kunnen opgeven welke functie moet worden aangeroepen, en de functies die moeten worden aangeroepen moeten een variabel aantal/type parameters hebben?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • CAPSLOCK2000
  • Registratie: Februari 2003
  • Laatst online: 11-09 21:28

CAPSLOCK2000

zie teletekst pagina 888

Topicstarter
bobo1on1 schreef op dinsdag 18 augustus 2009 @ 19:38:
Dit misschien dan:

C:
1
2
3
4
5
6
7
8
9
10
11
int functieA(int arg1, int (*p_functieA)(int, int(*)(), int(*)()), int (*p_functieB)(int, int(*)(), int(*)()))
{
  p_functieB(arg1, p_functieA, p_functieB);
  return 0;
}

int functieB(int arg1, int (*p_functieA)(int, int(*)(), int(*)()), int (*p_functieB)(int, int(*)(), int(*)()))
{
  p_functieA(arg1, p_functieA, p_functieB);
  return 0;
}


Die controleert of je genoeg argumenten aan de functiepointer meegeeft, alleen niet of de functiepointers dit je als argument meegeeft ook het juiste aantal argumenten moeten hebben.
Tnx, dit is de beste oplossing dusver. Het blijft een puinhoop, maar nu kan de compiler tenminste een beetje helpen, en typedef helpt ook nog wat.

Heb je nog een suggestie om mijn struct constructie bruikbaar te maken? Ik vond het namelijk wel makkelijk om zoveel mogelijk argumenten in structs mee te geven, het zijn er namelijk nogal veel.

This post is warranted for the full amount you paid me for it.


Acties:
  • 0 Henk 'm!

  • cpt.spiff
  • Registratie: Augustus 2009
  • Laatst online: 20-02 14:29
Mijn C zonder ++ is een beetje roestig, maar je kunt de recursie doorbreken wanneer je de 'Settings'-struct als pointer kunt doorgeven ipv by value. In dat geval kun je namelijk deze struct eerst pre-declaren:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Settings;

typedef int (*MijnFunctie)( struct Settings *settings);

typedef struct Settings {
  MijnFunctie functieA;
  MijnFunctie functieB;
  int arg3;
} Settings; 

int FuncA( Settings *settings)
{
  return settings->functieB( settings);
}

int FuncB( Settings *settings)
{
  return settings->functieB( settings);
}

Settings s = {FuncA, FuncB, 0};

Acties:
  • 0 Henk 'm!

  • CAPSLOCK2000
  • Registratie: Februari 2003
  • Laatst online: 11-09 21:28

CAPSLOCK2000

zie teletekst pagina 888

Topicstarter
farlane schreef op dinsdag 18 augustus 2009 @ 20:11:
Deze functie is gedefinieerd met een variabel aantal argumenten, niet zonder argumenten.
bedankt, nu snap ik ook waarom het werkte.
Als ik het goed begrijp wil je @runtime kunnen opgeven welke functie moet worden aangeroepen, en de functies die moeten worden aangeroepen moeten een variabel aantal/type parameters hebben?
Ik wil inderdaad dynamisch kunnen kiezen welke functies gebruikt worden. Het aantal argumenten staat vast, maar bevat onder andere een pointer naar de functie zelf. Dat geeft een cirkel definitie.

Laat ik de situatie maar iets verder uit leggen. Ik ben een AI aan het schrijven voor een spelletje. De AI moet zetten vooruit denken. Het spel is asymetrisch, daarmee bedoel ik dat de twee spelers andere mogelijkheden hebben. Denk bijvoorbeeld aan gokspelletjes, waarbij voor de deler andere regels gelden dan voor de spelers.

wat ik wil is:
spelerA()
{
if (diepte = 0)
return spelwaarde;
else
kies de beste zet afhankelijk van de beste zet van spelerB
}

spelerB()
{
if (diepte = 0)
return spelwaarde;
kies de beste zet afhankelijk van de beste zet van spelerA
}


Speler A kijkt dus naar welke zetten speler B in de volgende beurt kan doen. Speler B kijkt weer naar de volgende beurt van Speler A, en zo verder tot er een bepaalde grens is bereikt. (Dit staat bekend als het MiniMax algoritme).

SpelerA en spelerB kunnen verschillende strategieen gebruiken. Ik gebruik pointers om de strategie door te geven.

This post is warranted for the full amount you paid me for it.


Acties:
  • 0 Henk 'm!

  • CAPSLOCK2000
  • Registratie: Februari 2003
  • Laatst online: 11-09 21:28

CAPSLOCK2000

zie teletekst pagina 888

Topicstarter
cpt.spiff schreef op dinsdag 18 augustus 2009 @ 20:21:
Mijn C zonder ++ is een beetje roestig, maar je kunt de recursie doorbreken wanneer je de 'Settings'-struct als pointer kunt doorgeven ipv by value. In dat geval kun je namelijk deze struct eerst pre-declaren:

C:
1
2
3
4
5
struct Settings;
typedef int (*MijnFunctie)( struct Settings *settings);
typedef struct Settings { 

<knip>
Het werkt! Ik heb wel nog even de staalborstel moeten gebruiken, en de pointer er uit gesloopt, 1 sterretje minder dus :) De doorbraak voor mij was het gebruik van "struct" in de MijnFunctie typedef.


C:
1
2
3
4
5
struct Settings;
typedef int (*MijnFunctie)( struct Settings settings);
typedef struct Settings { 

<knip>


Ik was vergeten dat je structs ook kan pre-declaren, ik probeerde het via functie typedefs op te lossen. Dit is de mooiste constructie.

Bedankt allemaal voor het meedenken, alleen had dit me veel te lang gekost. M'n code is zo weer leesbaar. tnx

This post is warranted for the full amount you paid me for it.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

cpt.spiff schreef op dinsdag 18 augustus 2009 @ 20:21:
Mijn C zonder ++ is een beetje roestig, maar je kunt de recursie doorbreken wanneer je de 'Settings'-struct als pointer kunt doorgeven ipv by value. In dat geval kun je namelijk deze struct eerst pre-declaren:
Onjuist, althans, wat je zegt klopt wel, maar een ongedefinieerde struct kun je ook gewoon by value als functie-argument gebruiken bij een functiedeclaratie. Het is op dat moment namelijk nog niet van belang hoe die struct eruit ziet - dat wordt pas belangrijk als je die functie zelf gaat definieren. Je voorstel werkt dus ook door de Settings struct by value te passen.

Dit kan dus ook:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct Settings; 

typedef int (*MijnFunctie)( struct Settings settings); 

typedef struct Settings { 
  MijnFunctie functieA; 
  MijnFunctie functieB; 
  int arg3; 
} Settings;  

int FuncA( Settings settings) 
{ 
  return settings.functieB( settings); 
} 

int FuncB( Settings settings) 
{ 
  return settings.functieB( settings); 
} 

[ Voor 25% gewijzigd door .oisyn op 19-08-2009 11:02 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1