Fichiers vs Fonction vs Prototype

Bonjour a Tous,

En suivant des MOOC sur le C, il est expliqué, que si l'on veut créer une fonction, il faut créer son prototype avant la boucle Main. Et si on veut séparer son code en fichiers, mettre les prototypes dans le .h te les fonctions dans le .c

Jusque la, pas de problème.

Mais pour Arduino, jusqu’à maintenant, j'ai toujours créer des fonctions (de type Void) sans prototype et en les plaçant après le Void Loop, et ça marche nickel...

Savez vous pourquoi, il n'y a pas besoin des prototypes avec Arduino ?

Je cherche a séparer mon code (Arduino) en plusieurs fichiers, si les prototypes ne sont pas utiles, pourquoi faire le .h

Es ce que l'explication ne viendrait pas du faite que les fonctions que j'ai créé ne retourne pas de valeurs ?

Merci

greg06:
Savez vous pourquoi, il n'y a pas besoin des prototypes avec Arduino ?

Bonjour,

Parce que à partir du fichier .ino, l'IDE arduino génère un 'vrai' fichier C++ et mets les déclarations de fonctions (a ta place) dans ce fichier

Si tu crées des fichier .cpp, il est impératif de suivre les règles c++ en particulier les déclarations en avant.
Donc il faut des .h

Au top, Merci à vous.

Ce que dit pepe est vrai mais nécessite une bonne connaissance du C/C++.

Ce qu’il faut retenir c’est le que compilateur doit avoir été averti de l’existance d’une fonction avant tout appel a cette fonction.
Perso je ne suis pas un vrai programmeur et je pré-déclare systématiquement.
Si je décompose mon programme en plusieurs fichiers :

  • Pour les fichiers supplémentaires j’utilise les extensions c ou cpp.
  • Pour chaque fichier j’écris le fichier d’entête *.h qui contient les déclarations des fonctions ou des classes.
  • J’inclue ces fichiers *.h dans le fichier *.ino à l’aide de # include …

La syntaxe pour déclarer ces fichiers diffère selon l’emplacement des fichiers d’entête.
L’IDE fabrique le fichier “makefile” selon ses propres règles qui déterminent 3 emplacements officiels :
1 → dans la partie “core” de l’IDE pour les bibliothèques qui dépendent directement d’Arduino
2 → dans un autre répertoire de l’IDE pour les bibliothèques qui dépendent de tierces parties validées par arduino
3 → dans le répertoire “libraries” de ton répertoire personnel arduino pour toutes les autres bibliothèques.

Dans ce cas la syntaxe est #include <nom-fichier.h>

Si tu décompose ton programme en plusieurs fichiers ces fichiers seront dans le répertoire qui contient le fichier *.ino.
Il faudra alors dire au compilateur d’aller les chercher dans ce répertoire courant.
Cela se fait en remplaçant les < > par des " " (c’est une règle du C/C++)

include “nom-fichier.h”

Dernier point : si tu utilises des variables globales :
Les variables globales sont définies dans le fichier *.ino.
Une variable ne doit être déclarée qu’une seule fois mais chaque fichier est compilé séparément.
Pour les fichiers C/Cpp il faut prévenir le compilateur que ces variables ont déjà été déclarées ailleurs.

Cela se fait en ajoutant le mot clé “extern” :
Fichier *.ino :
int machin ; // déclaration
Fichier C/Cpp :
extern int machin ; // annonce au compilateur que la variable machin est de type int et qu’elle a déjà été déclarée ailleurs.

Au top !

Dernier point : si tu utilises des variables globales :

Bien anticiper, effectivement je suis en train de regarder cette partie, j'attaque ce soir et ce weekend.

Merci

68tjs:
Cela se fait en ajoutant le mot clé "extern" :
Fichier *.ino :
int machin ; // déclaration
Fichier C/Cpp :
extern int machin ; // annonce au compilateur que la variable machin est de type int et qu'elle a déjà été déclarée ailleurs.

Bonjour,

Je constate que de plus en plus, y compris dans les tutos et cours sur internet on emploie déclaration pour définition

De ce que j'ai retenu de mon apprentissage du C qui commence à remonter à pas mal d'années c'est que:
int machin ; // c'est une définition (qui vaut aussi déclaration)
extern int machin ; // c'est une déclaration

Suis je obsolète? Est ce que la terminologie a changé (sans qu'on me prévienne :slight_smile: )?

Suis je obsolète? Est ce que la terminologie a changé (sans qu'on me prévienne :) )

Non tu te mets simplement à ma place quand je vois utiliser les termes pull-up et pull-down a tort et à travers en faisant simplement référence à la position géographique sur le schéma et en oubliant, méconnaissant, méprisant totalement le coté fonctionnel.

Donc promis j'essayerais de me rappeler de ta mise au point.

Etant un éternel optimiste j'ose espérer que, peut être, d'autres se rappelleront mes rappels incessant.

Pour vos projets Arduino, vous utilisez plutôt les variables propres au fonctions ou des variable globales ?

Je début en C et Arduino et j'essaye d'avoir les meilleurs "bonne pratique"

Merci

Bonjour,

On utilise des variables globales uniquement si c'est nécessaire. Autrement on utilise des variables locales.

C'est vrai que dans beaucoup d'exemples de code arduino, toutes les variables sont définies au début du fichier .ino.
A mon avis c'est à proscrire, ça va complètement à l'encontre de la modularité. De plus quand on analyse une fonction, il faut retrouver les variables pour savoir de quoi il s'agit et en plus on ne sait jamais si c'est une vraie variable globale modifiée par ailleurs ou si c'est simplement une variable locale qui a été déclarée en globale.

68tjs:
Etant un éternel optimiste j'ose espérer que, peut être, d'autres se rappelleront mes rappels incessant.

L'espoir fait vivre! :slight_smile:

Salut,

Merci pour ton retour. Effectivement beaucoup de tuto, mooc, livre ect... utilise les variables globale pour Arduino.

Quand tu dis

ça va complètement à l'encontre de la modularité.

, tu veux dire quoi ?

J'essaye de comprendre le pour et le contre de ces deux philosophies et j'ai l'impression que les variables globales on l'air plus facile a coder ( moins de gymnastique de fonction a fonction...)

J'ai une déclaration de variable avec enum {value1, value2,...} dans le .ino

Evidement ces variables se retrouvent dans une fonction que je souhaite déplacer dans un autre fichier.
Donc dans le .c je déclare extern enum {value1, value2,...}

J'ai ce message d'erreur

error: a storage class can only be specified for objects and functions

Avez vous un conseil ?

Merci

Bonjour,

enum {value1, value2} ce n'est pas la définition d'une variable, mais la définition d'un type énuméré.

la définition d'une variable serait enum {value1, value2} val;
elle pourrait être partagée par extern enum {value1, value2} val;, mais la définition de l'enum entrerait en conflit avec la définition de l'enum dans la définition de la variable dans le fichier ou elle est définie.

C'est pour ça qu'on utilise des enum nommés

dans le .h

enum EVAL {value1, value2};  // définition de l'enum EVAL
extern EVAL val;  // déclaration de la variable val

val est défini dans dans un .cpp

EVAL val;   // définition de la variable val

idem pour les class

Merci

Je comprend nomer enum, mais pourquoi

extern EVAL val; // déclaration de la variable val

ca vaut int val

Je suis en train de réaliser une machine pour résoudre les Rubik's cube.
Pour tester mon solver, j'utilise enum pour attribuer les couleurs au face du cube.

Et je souhaiterai déplacer les void configuration 1 & 2 dans un autre fichier.

version simplifié du code :

enum {white, blue, green};
byte cubeFace[6][8];
byte choix=1;

void setup(){
  if (choix==1) configuration1();
  else if (choix==2) configuration2();
}

void loop(){
  solver();
}

void solver(){
  if (cubeFace[0][4]==white && cubeFace[2][3]==blue) turnFace();
}

void configuration1(){
  cubeFace[0][2]=white;
  cubeFace[1][5]=blue;
  cubeFace[2][8]=green;
  //ect...
}

void configuration2(){
  cubeFace[0][2]=blue;
  cubeFace[1][5]=green;
  cubeFace[2][8]=white;
  //ect...
}

Es ce une bonne pratique pour enum ?
Et donc si je nomme enum je devrait pouvoir le déclarer dans le .h

Bonjour,

Tu utilises les enum comme de simples constantes numériques.
Ceci est autorisé en C++ car ce langage n'est pas très strict avec les correspondances de types

En toute rigueur il aurait fallu faire

enum COULEUR {white, blue, green};
COULEUR cubeFace[6][8];

Pour répondre à ta question tu peux mettre ton enum dans un .h et appeler ce .h dans le fichier ou seront définis configuration 1 & 2.

Encore Merci !

C’était justement le sujet du poste et j'ai oublié de mettre les prototypes dans le code précédent.

void solver();
void configuration1();
void configuration2();

:-[

Desolé mais j'arrive pas comprendre la différence entre :

;COULEUR cubeFace[6][8];
byte cubeFace[6][8];

Dans les deux cas je créé une variable, la première de type int et la deuxième du type que je choisi, dans ce cas byte.

Mais quel avantage de passer par ce que tu proposes ?

Moi je ne propose rien, j'explique le fonctionnement des enum

COULEUR cubeFace[6][8]; -> crée un tableau de variables de type COULEUR
byte cubeFace[6][8]; -> crée un tableau de type byte

Comme je l'ai expliqué, en C++ il y a un transtypage automatique entre un type enum (comme COULEUR) et un numérique
L'inverse n'est pas forcément vrai
Si tu déclares COULEUR cubeFace[6][8]; et que tu fais cubeface[0][0]=1, le compilateur devrait donner une erreur (ce que ne fait pas le compilateur de l'IDE arduino).

D'autres langages sont beaucoup moins permissifs que le C++.

pepe:
Au final, on peut être amené à écrire un même programme très différemment selon que l'on cherche à avoir un code très rapide, un code qui consomme peu de mémoire vive, ou un code qui consomme peu de mémoire programme.

Ou un code lisible, maintenable et réutilisable :grin:

Merci pour toutes ces explications.