Conservation de l'information

Postby teaniel » Wed May 30, 2007 12:00 am

Bonjour

Petit souci de programation (hew/kd30) de mon r8/c13, monté sur ma platine dessais :
J'ai créé un programme (assez volumineux, soit), pour interpréter des commandes envoyées pare UART0. Dedans, une structure comportant un nombre de commandes est initiualisée dans un sous-programme. Cependant, ces écritures semblent ne pas fonctionner (quand je passe dessus avec KD30, les instructions n'ont aucun effet, ce qui provoque le blocage du programme un peu plus loin, du fait que j'utilise des pointeurs vers des fonctions). Si, toujours avec KD30, je modifie manuellement les valeurs de ces variables, ca fonctionne.
Quelqu'un aurait une explication?

Cordialement,
Marc'
teaniel
 
Posts: 29
Joined: Fri Jan 17, 2014 4:36 pm

Postby alfa » Wed May 30, 2007 12:00 am

bonjour,

Il faudrait être un peu plus clair dans ta présentation du problème avec au besoin le code source qui semble ne pas fonctionner.

Amicalement.
alfa
 
Posts: 14
Joined: Fri Jan 17, 2014 4:36 pm

Postby ebonv » Wed May 30, 2007 12:00 am

bonjour,

si j'ai bien compris ton programme initialise des pointeurs en mémoire ram ou flash
Si c'est en flash, je crois que que des "autorisations" sont à prévoir, si c'est en ram, si ton programe est volumineux n'a tu pas un conflit de pile?

A+

etienne
ebonv
 
Posts: 74
Joined: Fri Jan 17, 2014 4:35 pm

Postby teaniel » Wed May 30, 2007 12:00 am

Bonjour,

Désolé, c'est vrai que ce texte est complètement incompréhensible...
Je vais essayer d'être plus clair.

Bout de code :

typedef void (*tFonction)(char *buffer);
struct sUART0_buf {
char *buffer;
char pos;
tFonction Fonction;
} UART0_buf;

void InitBuffer();
{
...
...
UART0_buf.Fonction = 0; // Ligne exécutée, mais sans effet
... // Ici, UART0_buf.Fonction == 0x2727
...
}

void Analyse( const buffer )
{
...
...
if (UART0_buf.Fonction)
UART0_buf.Fonction(buffer); // Ne devrait pas être exécuté, mais l'est quand même du fait que Fonction n'est pas nul. Plantage.
...
...
}

Voila.
Ces fonctions font partie d'un (prétendu) interpréteur de commandes, qui se sert de Fonction pour affecter une fonction d'interprétation à l'instruction qui vient d'être lue sur le port UART0.
On aura évidemment compris que 0x2727 n'est l'adresse d'aucune fonction valide, ce qui provoque le bloquage du programme dans Analyse.

Cette mésaventure, ou quelque chose d'approchant serait-elle déjà arrivée à quelqu'un?

Cordialement,
Marc
teaniel
 
Posts: 29
Joined: Fri Jan 17, 2014 4:36 pm

Postby teaniel » Wed May 30, 2007 12:00 am

Bonsoir

oops Etienne, j'étais en train de rédiger quand tu as posté...

En fait je ne sais pas trop, pour la mémoire, tout cela est géré par le C. Je ne pense pas que ce soit mis en flash, supposant que cela soit lié à une action volontaire de la part du programmeur, que je n'ai pas posée.
Pour ce qui est de la pile, je ne pense pas, puisque les deux zones (heap et pile) sont disjointes (tailles 300h heap et 80h pile), et je n'utilise pas la récursion dans mon code.
Merci de ta suggestion

@++
Marc
teaniel
 
Posts: 29
Joined: Fri Jan 17, 2014 4:36 pm

Postby alfa » Wed May 30, 2007 12:00 am

Bonjour

Tu utilises un type crée 'tFonction'. Il faudrait détaillé la déclaration de ce type.

Attention de ne pas confondre :
a./ la déclaration de fonction
b./ la déclaration de 'pointeur sur une fonction'.
c./ la utilisation de 'pointeur sur une fonction'.

En C, SI tu veux créer une variable dont le contenu te permet d'appeler une fonction bien identifiée,
=> ALORS il faut passer par la notion de POINTEUR SUR UNE FONCTION.
__________________________________________________________________________
Ci après 2 exemples:

1./ Appel d'une fonction avec une interface minimale (cad. pas de paramètre ET pas de valeur de retour)

// prototype de la fonction (dans un .h typiquement)
void UneFonction();
// corps de la fonction (dans un .c typiquement)
void UneFonction()
{ // corps de la fonction...
}
// déclaration en global de la variable pFunc qui servira à:
// 1./ A mémoriser UN POINTEUR SUR UNE FONCTION
// 2./ A appeler effectivement LA FONCTION POINTéE
// On dit et on écrit, que pFunc EST...
// Un pointeur sur une fonction prenant comme arguments :
//______|___RIEN
//______|_____|
void (*pFunc) ( );
//_|__<---- et cette fonction retourne RIEN.
//
main()
{ // initialisation du pointeur pFunc (ici donc en dynamique)
pFunc = UneFonction;

// appel effectif de la fonction pointée par pFunc
// (ici ou dans n'importe quel sous-programme du module car pFunc est déclarée en global)
(*pFunc)(); // le corps de UneFonction vient d'être exécutée

}

__________________________________________________________________________


2./ Appel d'une fonction avec une interface plus réaliste , soit 2 paramètres, ET une de valeur de retour (=>le max en C,C++)

// prototype de la fonction (dans un .h typiquement)
char UneFonction(char *pBuf, int a);
// corps de la fonction (dans un .c typiquement)
char UneFonction(char *pBuf, int a)
{ return *(pBuf+a); // retourne le aième char du buffer pointé par pBuf
}
// déclaration en global de la variable pFunc qui servira à:
// 1./ A mémoriser UN POINTEUR SUR UNE FONCTION
// 2./ A appeler effectivement LA FONCTION POINTéE
// On dit et on écrit, que pFunc EST...
//____Un pointeur sur une fonction prenant comme arguments :
//_____|_____Un pointeur sur un char,
//_____|______|
//_____|______|__et_Un entier
//_____|______|_____|
char (*pFunc)(char *, int);
//_|__<---- et cette fonction retourne un char.
//
main()
{ // les déclartion suivantes sont utilisées pour l'exemple:
// 1./ le passage des paramètres
// 2./ le char retourné par la fonction
char UnPointeurSurChar[10]; int UnEntier=3;
char MonResDeFonction;

// initialisation du pointeur pFunc (ici donc en dynamique)
pFunc = UneFonction;

// appel effectif de la fonction pointée par pFunc
// (ici ou dans n'importe quel sous-programme du module car pFunc est déclarée en global)
MonResDeFonction = (*pFunc)( UnPointeurSurChar, UnEntier);

}

__________________________________________________________________________


Il faut donc bien comprendre la notion d'utilisation de 'pointeur sur une fonction' en C:

=> En fait, il faut voir la LECTURE d'une variable de type 'pointeur une fonction' comme l'APPEL EFFECTIF de la fonction.
Le C/C++ interprète cette lecture par l'appel effectif de la fonction pointée.

Je suppose que tu sais exactement ce que signifie 'lecture de variable' en C/C++:
=> Je te donne un guide: tu te mets à la place de la machine et tu regardes si une variable doit être lue pour exécuter le programme
( en principe, TOUT ce qui n'est pas à gauche d'un signe égal est considéré comme lu par le C)

Par exemple;
int i; //....
.
.
if(i==2) // ici, i vient d'être lu (car il faut bien lire 'i' pour savoir s'il vaut '2'.
{ ... }

Ainsi, si je reprend l'exemple 2./, je peux écrire en C le code suivant:

if( (*pFunc)( UnPointeurSurChar, UnEntier) != 0 ) // APPEL (car LECTURE) de la fonction pointé ET test de la valeur retournée...
{ // ici, la fonction pointé par pFunc a retourné un char non nul
}



Dès que tu auras bien vu et compris le principe, tu peux passer aux tableaux de pointeurs sur des fonctions.



Cordialement.
alfa
 
Posts: 14
Joined: Fri Jan 17, 2014 4:36 pm

Postby teaniel » Wed May 30, 2007 12:00 am

Merci, alpha pour toutes ces précisions.

Je pense que je colle bien à ta description, et je donne quelques précisions supplémentaires :
J'utilise les extensions au language C autorisées par Hew et NC30. En effet, plutot adepte du C++, je trouve la déclaration de type (typedef) bien pratique. C'est ainsi que je déclare tFonction. Par ailleurs, j'ai découvert, après quelques essais que l'utilisation d'un pointeur de fonction (appel de fonction par son pointeur) pouvait se faire sans déréférencement :

int maFonction( arguments ); // Déclaration d'une fonction
typedef int (*tFonction)( arguments ); // Type pointeur sur fonction
// (compatible avec maFonction)
// Pas du C mais autorisé avec
// NC30 (voir extensions du
// language dans manuel NC30)
void main()
{
/* Assignation de l'adresse de maFonction au pointeur
maFonctionPointee */
tFonction maFonctionPointee = maFonction;
/* Du fait de l'utilisation de typedef plus haut, tFonction
est considéré par NC30 comme un type de données déclaré,
que l'on peut donc utiliser comme tel. */
int resultat = maFonctionPointee( mesArguments );
/* Après essais, cette syntaxe appelle effectivement maFonction
avec les bons arguments, et retourne la valeur donnée.
Je n'ai pas trouvé de documentation sur ce point,
il n'est donc pas garranti qu'il soit réellement valide.
Par contre je sais qu'il s'agit d'une erreur en C et C++
standards */
}

Je trouve intéressant de parler de cet aspect de la programation, car ce genre de méthode permet de créer un code particulièrement compact, remplacant avantageusement autant par la taille du code que par la vitesse d'exécution les switch()...case ou les if... else if. Il suffit de trouver une méthode de calcul permettant d'obtenir un indice dans une table, et l'appel est immédiat.
Un autre exemple d'utilisation : Procédure évènementielle pour recevoir des données depuis UART0 : ca marche un peu comme les gestionnaires d'évènements du C++ builder.

Le client déclare une fonction de prise en compte
void Reception( char *buffer );
dans laquelle il prend en compte et utilise la chaine recue du canal de communication.
Dans la bibliotheque UART0 (que j'ai écrite), un typedef déclare un type de fonction ayant le même prototype ( typedef void (*tGetFunc)( char *buffer ); ).

Pour déclencher la réception des caractères, le client appelle une fonction de la bib UART0 : UART0_get( int nombre, tGetFunc recu ), qui initialise une structure avec un buffer de la bonne taille (nombre+1), l'adresse de la fonction donnée dans le deuxième argument, et quelques données internes, puis autorise l'interruption 17 à l'adresse d'une fonction de réception, et rend la main (la reception est alors asynchrone). Le client peut continuer ses bêtises pendant que la réception se fait sans lui.

La fonction d'interruption détecte la fin de l'émission, et appelle alors la fonction de réception du client par l'intermédiaire de son pointeur (UART0_getbuf.RetFunc(buffer) , qui dispose alors des données reçues.

Pour permettre de recevoir de nouvelles données, il est alors nécessaire que dans le code de Reception figure un nouvel appel à UART0_get.

Cordialement,
Marc
teaniel
 
Posts: 29
Joined: Fri Jan 17, 2014 4:36 pm

Postby teaniel » Wed May 30, 2007 12:00 am

arf dsl c'est illisible, le gestionnaire de message a supprimée toute mon indentation
teaniel
 
Posts: 29
Joined: Fri Jan 17, 2014 4:36 pm

Postby alfa » Wed May 30, 2007 12:00 am

Re bonjour Marc

Je suis content que mes précisions te renseignent.

Le 'typedef' est bien sûr très utile pour:
1./ Pouvoir lire plus facilement le code
2./ Procéder par niveau d'abstraction (fonction, pointeur sur, pointeur sur pointeur,...)
3./ Eviter des parenthésage vite illisible.


Je ne sais plus du coup si tu as encore un problème ?

Tu écris:
.....
int resultat = maFonctionPointee( mesArguments );
/* Après essais, cette syntaxe appelle effectivement maFonction
avec les bons arguments, et retourne la valeur donnée.
Je n'ai pas trouvé de documentation sur ce point,
il n'est donc pas garranti qu'il soit réellement valide.
Par contre je sais qu'il s'agit d'une erreur en C et C++
standards */

Qu'entends-tu par 'Je n'ai pas trouvé de documentation sur ce point,...' ?

Si tu veux traiter une trame d'informations, le principe de codage souvent retenu est le suivant:
On commence par un CODE (souvent un octet convient) suivi par des champs contenant des paramètres en relation avec le CODE
( on appelle cela un 'message' )

A/ on lit ce code (1 char du buffer de réception)
B/ on pointe le tableau des fonctions s'occupant du décodage de chaque message ( 1 code => 1 fonction)
C/ on appelle la fonction.
A/B/C/ se résume à une instruction C du type:
( *(pTable+Buffer[0]) ) ( &Buffer[1] );
C/ dans chaque fonction du type
void FonctionCodeXX( char *pBuf)
{ // ici pBuf pointe sur le 2ième octet de la trame => début des champs contenant des paramètres
//...
}

Cordialement

Hervé.



alfa
 
Posts: 14
Joined: Fri Jan 17, 2014 4:36 pm

Postby teaniel » Wed May 30, 2007 12:00 am

Bonjour, et désolé du temps d'absence.

Paralfa le 30/06/2006 15:41:01 Je ne sais plus du coup si tu as encore un problème ?


Ce n'est pas l'architecture du programme qui me pose problème, mais le fonctionnement d'une partie de son code.
En fait c'est Etienne qui l'a le mieux exprimé. Ce sont des affectations de pointeurs qui ne fonctionnent pas.
Comme je laisse la gestion de la mémoire à NC30, je suppose qu'il a utilisé une plage légale pour y placer ces pointeurs... Supposition renforcée par le fait que j'arrive à modifier leur valeur manuellement avec KD30.
En pratique je cherche l'avis de quelqu'un qui aurait déjà résolu un tel problème.

Paralfa le 30/06/2006 15:41:01 Qu'entends-tu par 'Je n'ai pas trouvé de documentation sur ce point,...' ?

En fait c'est sur la syntaxe exacte de l'appel d'une fonction par un pointeur : qu'est-ce qui est juste "(*funcptr)( arguments )" ou "funcptr( arguments )" ? (les deux semblent fonctionner avec NC30).

Paralfa le 30/06/2006 15:41:01 On commence par un CODE (souvent un octet convient) suivi par des champs contenant des paramètres en relation avec le CODE
( on appelle cela un 'message' )


C'est en effet ainsi (grosso-modo) que j'ai réalisé mon lecteur.


Cordialement,
Marc.
teaniel
 
Posts: 29
Joined: Fri Jan 17, 2014 4:36 pm


Return to R8C/13 (01-2006)

Who is online

Users browsing this forum: No registered users and 1 guest