Tableau de fonctions-Pointeur de procédures

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
JagV12
Messages : 20
Inscription : sam. 06/janv./2018 11:39

Tableau de fonctions-Pointeur de procédures

Message par JagV12 »

Bonjour à toutes et tous,

En C, ils est courant d'utiliser les pointeurs de fonctions et de les regrouper en tableaux, comme dans cet exemple, trouvé sur internet :

Code : Tout sélectionner

 1  - #include <stdio.h>
 2  -
 3  - int sum(int x, int y) {return(x + y);}
 4  - int sub(int x, int y) {return(x - y);}
 5  - int mult(int x, int y) {return(x * y);}
 6  - int div(int x, int y) {if (y != 0) return (x / y); else  return 0;}
 7  - 
 8  - int main() 
 9  - {
10 -   int x, y, choice, result;
11 -   int (*ope[4])(int, int);    // <--- le tableau de pointeurs de fonction
12 -   ope[0] = sum;               // <--- et son remplissage
13 -   ope[1] = sub;
14 -   ope[2] = mult;
15 -   ope[3] = div;
16 -   printf("Enter two integer numbers: ");
17 -   scanf("%d%d", &x, &y);
18 -   printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: ");
19 -   scanf("%d", &choice);
20 -   result = ope[choice](x, y); // <--- Utilisation d'un élément du tableau
21 -   printf("%d", result);
22 -   return 0;
23 - }
J'essaie de faire l'équivalent en PureBasic (mes fonctions ont 1 Char et une String comme paramètres et retournent une String) mais je ne vois pas comment ré-écrire la ligne 20 "result = ope[choice](x, y)". J'ai donc ce début :

Code : Tout sélectionner

EnableExplicit

Macro HexFormat(Prefix, Value, Size)
  Prefix + RSet(Hex(Value), Size, "0")
EndMacro


Procedure.s fChar0Decoder(aChar.a, sString.s)
  Debug "fChar0Decoder, Char = " + HexFormat("0x", aChar, 2) + " = '" + Chr(aChar) + "'"
  Debug "String = '" + sString + "', String Length = " + Len(sString)
  ProcedureReturn "fChar0Decoder"
EndProcedure
    
Procedure.s fChar1Decoder(aChar.a, sString.s)
  Debug "fChar0Decoder, Char = " + HexFormat("0x", aChar, 2) + " = '" + Chr(aChar) + "'"
  Debug "String = '" + sString + "', String Length = " + Len(sString)
  ProcedureReturn "fChar1Decoder"
EndProcedure
    
Procedure.s fChar2Decoder(aChar.a, sString.s)
  Debug "fChar0Decoder, Char = " + HexFormat("0x", aChar, 2) + " = '" + Chr(aChar) + "'"
  Debug "String = '" + sString + "', String Length = " + Len(sString)
  ProcedureReturn "fChar2Decoder"
EndProcedure
    
Procedure.s fChar3Decoder(aChar.a, sString.s)
  Debug "fChar0Decoder, Char = " + HexFormat("0x", aChar, 2) + " = '" + Chr(aChar) + "'"
  Debug "String = '" + sString + "', String Length = " + Len(sString)
  ProcedureReturn "fChar3Decoder"
EndProcedure



ProcedureC.i iCharDecoderFuncAddress(Function.i)
  ShowCallstack()                                                  ; <--- Je voulais voir la pile mais la fenêtre ouverte ici n'est pas celle que j'attendais
  Debug "Function.i = " + HexFormat("0x", Function, 16)
  ProcedureReturn #Null
EndProcedure

Define iProcedureIndex.i, iResult.i, sResult.s
Dim fCharDecoder.i(3)

sResult = fChar0Decoder(75, "Test0") : Debug "Direct Call : sResult = '" + sResult + ~"'\n"
sResult = fChar1Decoder(76, "Test1") : Debug "Direct Call : sResult = '" + sResult + ~"'\n"
sResult = fChar2Decoder(77, "Test2") : Debug "Direct Call : sResult = '" + sResult + ~"'\n"
sResult = fChar3Decoder(78, "Test3") : Debug "Direct Call : sResult = '" + sResult + ~"'\n"

fCharDecoder(0) = @fChar0Decoder()
fCharDecoder(1) = @fChar1Decoder()
fCharDecoder(2) = @fChar2Decoder()
fCharDecoder(3) = @fChar3Decoder()

For iProcedureIndex = 0 To 3
;   fCharDecoder(iProcedureIndex)('N', "Test3")                    ; <--- Tentative d'utilisation du tableau => Syntax error !
  iResult = iCharDecoderFuncAddress(fCharDecoder(iProcedureIndex))
  Debug "iResult = " + iResult + ~"\n"
Next

End
Comment codez-vous ça ? Surtout avec des paramètres entrants...

Par avance, merci pour votre aide
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: Tableau de fonctions-Pointeur de procédures

Message par G-Rom »

Salut, peut être avec des prototypes :

Code : Tout sélectionner


Procedure Test()
  Debug "Test"
EndProcedure

Procedure.a Test2(text.s)
  Debug text 
  ProcedureReturn 42  
EndProcedure


Prototype Foo()
Prototype.a Foo2(text.s)


Structure Function
  StructureUnion  
    Foo.Foo  
    Foo2.Foo2
  EndStructureUnion  
EndStructure

Dim Functions.Function(9)


Functions(0)\Foo = @Test()
Functions(1)\Foo2 = @Test2()


Functions(0)\Foo()
Functions(1)\Foo2("Hello")


Avatar de l’utilisateur
Naheulf
Messages : 191
Inscription : dim. 10/mars/2013 22:22
Localisation : France

Re: Tableau de fonctions-Pointeur de procédures

Message par Naheulf »

Je t'invites à regarder du coté des fonctions CallCFunction(), CallCFunctionFast(), CallFunction(), CallFunctionFast(), des prototypes et des interfaces. Selon ce que tu veut faire et ce que tu connais au moment de la compilations la méthode à utiliser sera différente.
JagV12
Messages : 20
Inscription : sam. 06/janv./2018 11:39

Re: Tableau de fonctions-Pointeur de procédures

Message par JagV12 »

@G-Rom : MERCI =>Bonne nouvelle, j'ai quelque chose qui fonctionne. Je suis parti de l'exemple donné dans l'aide de "Runtime" et, grace à vous, j'y ai ajouté les paramètres d'entrée dans "Prototype.s Function(Param1.a, Param2.s)". Mais je m'aperçois que je suis un cran trop compliqué (appel d'une fonction grâce à son nom), il faut que je simplifie en reprenant votre exemple et en particulier le mot clé Prototype. Comme toutes mes fonctions/procédures de ce tableau ont les mêmes paramètres en entrée et en sortie, je devrais pouvoir me passer de

Code : Tout sélectionner

Structure Function
  StructureUnion 
    Foo.Foo 
    Foo2.Foo2
  EndStructureUnion 
EndStructure
mais je garde ça en tête pour une autre fois...

@Naheulf : Merci également. Il semble en effet que "Prototype" soit le mot clé à torturer ces prochaines heures... à moins que ce ne soit lui qui me torture...

La suite tout de suite (comme on disait à l'époque des 68705 et des 4 lignes à retard vertes)
JagV12
Messages : 20
Inscription : sam. 06/janv./2018 11:39

Re: Tableau de fonctions-Pointeur de procédures

Message par JagV12 »

Voilà donc ce que j'obtiens en simplifiant le code de G-Rom :

Code : Tout sélectionner

EnableExplicit

Procedure.s Test1(aChar.a, text.s)
  Debug "Test : " + aChar
  ProcedureReturn "Test1 OK"
EndProcedure

Procedure.s Test2(aChar.a, text.s)
  Debug "Test : " + aChar
  ProcedureReturn "Test2 OK"
EndProcedure


Prototype.s Bar(aChar.a, text.s)
Structure Function
  Foo.Bar
EndStructure

Dim Functions.Function(9)
Functions(0)\Foo = @Test1()
Functions(1)\Foo = @Test2()


Debug Functions(0)\Foo(65, "Hi")
Debug Functions(1)\Foo(66, "Hello")
Puis-je faire plus simple ou le passage par une Structure est-il indispensable pour avoir un tableau de Procédures ?
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: Tableau de fonctions-Pointeur de procédures

Message par G-Rom »

Si tu veut avoir plusieurs type de fonctions, tu n'auras pas trop le choix
tu peut rajouté un type dans ta structure pour définir le type de fonction :
Structure Fonction
type.l
StructureUnion
MesPrototype...
endStructureUnion
EndStructure
JagV12
Messages : 20
Inscription : sam. 06/janv./2018 11:39

Re: Tableau de fonctions-Pointeur de procédures

Message par JagV12 »

Au contraire, même si je note le principe de l'Union pour une utilisation ultérieure, aujourd'hui, je n'ai besoin que d'un seul type de fonction : "Procedure.s Fonction0..9(aChar.a, sText.s)". Je cherche donc le strict minimum pour qu'un index puisse renvoyer vers la fonction correspondante du tableau.

Cela dit, quel est le rôle de "type.l" dans ton dernier exemple ? Tester une correspondance ?

Et ma question précédente reste d'actualité : Suis-je au strict minimum pour avoir un tableau de Procédures ? Ou puis-je encore simplifier ?
Dernière modification par JagV12 le sam. 04/avr./2020 16:30, modifié 1 fois.
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: Tableau de fonctions-Pointeur de procédures

Message par G-Rom »

le tableau en lui même ne peut pas être un tableau de type "prototype" ,d'ou la structure.
tu peut aussi stocké les pointeurs et faire appel a callfunctionfast ou faire un seul prototype pour ta fonction, libre à toi. ;)
JagV12
Messages : 20
Inscription : sam. 06/janv./2018 11:39

Re: Tableau de fonctions-Pointeur de procédures

Message par JagV12 »

J'ai légèrement édité mon précédent post (à relire éventuellement).

"callfunctionfast" et ses semblables sont limités en matière de paramètres d'entrée et de sortie (elle n'accepte pas les paramètres de type string, float, double et quad, et ne peut pas renvoyer des valeurs de type string, float, double ou quad. Il est vivement conseillé d'utiliser les prototypes à la place)

Donc il semble que je sois au plus simple possible compte tenu de mon besoin... sauf, bien sûr, si vous avez encore mieux...

Merci (à tous) pour votre rapidité !
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: Tableau de fonctions-Pointeur de procédures

Message par G-Rom »

dans ce cas, pas le choix, prototype. Quand au type de la structure plus haut , c'est juste un "flag" pour faire le bon choix dans l'union du dessous.
le type pourrais être une énumération que tu définis :
par exemple :

Code : Tout sélectionner

Enumeration 
  FUNCTION_TYPE_A ; proc.i( a.s ) 
  FUNCTION_TYPE_B ; proc()
  FUNCTION_TYPE_C ; proc.f( a.f , b.s )
  FUNCTION_TYPE_D ; proc.f()
EndEnumeration
Mesa
Messages : 1097
Inscription : mer. 14/sept./2011 16:59

Re: Tableau de fonctions-Pointeur de procédures

Message par Mesa »

Code : Tout sélectionner


Procedure sum( x,  y)
  ProcedureReturn(x + y);}
EndProcedure

Procedure sub( x,  y)
  ProcedureReturn(x - y);} 
EndProcedure

Procedure mult( x,  y)
  ProcedureReturn(x * y);} 
EndProcedure

Procedure div( x,  y)
  If y <> 0 
    ProcedureReturn(x / y)
  Else 
    ProcedureReturn 0;} 
  EndIf
  
EndProcedure


Global Dim tabfunc.i(4)
tabfunc(1)=@sum()
tabfunc(2)=@sub()
tabfunc(3)=@mult()
tabfunc(4)=@div()


Define x, y 

x=10
y=12


; Debug CallFunctionFast(tabfunc(1),x,y)


Procedure choice(choice, x, y)
  ProcedureReturn CallFunctionFast(tabfunc(choice),x,y)
  
EndProcedure
;   


For i=1 To 4
  Debug choice(i,x,y)
Next i

L'aide dit que
Note: CallFunctionFast: Cette fonction n'est pas très flexible car elle n'accepte pas les paramètres de type string, float, double et quad, et ne peut pas renvoyer des valeurs de type string, float, double ou quad. Il est vivement conseillé d'utiliser les prototypes à la place.
M.
Répondre