j'ai un projet autour d'un ESP32 qui commence à être conséquent et que j'ai découpé en plusieurs fichiers .cpp et .h à côté du fichier .ino
J'ai, entre autres, un fichier pour tout ce qui est mesures (mesures.cpp et mesures.h) et un fichier pour l'interface web (srvweb.cpp et srvweb.h)
Dans mesures.cpp j'ai déclaré une structure, une variable et un tableau que j'utilise surtout dans ce même fichier. Jusque là tout va bien.
struct SDATA {
float temp;
long tmillis;
// bool err; // les 2 bool pas encore utilisés
// bool valable;
};
SDATA last_temp; // dernière mesure
SDATA TabMesures[3600]; // toutes les mesures
Or, j'aimerai accéder à last_temp dans le fichier srvweb.cpp donc j'ai mis dans srvweb.h :
extern struct SDATA;
extern SDATA last_temp;
mais ça ne compile pas :
srvweb.h:20:1: error: a storage class can only be specified for objects and functions
extern struct SDATA;
^~~~~~
/home/c****/srvweb.h: In function 'void handleWebSocketMessage(void*, uint8_t*, size_t)':
/home/c****/srvweb.h:21:14: error: 'last_temp' has incomplete type
extern SDATA last_temp;
^~~~~~~~~
/home/c****/srvweb.h:20:15: note: forward declaration of 'struct SDATA'
extern struct SDATA;
^~~~~
In file included from /home/c****/JSON_essai.ino:21:
/home/c****/srvweb.h:20:1: error: a storage class can only be specified for objects and functions
extern struct SDATA;
^~~~~~
évidement si je ne mets rien, pas plus
/home/c****/srvweb.cpp: In function 'void handleWebSocketMessage(void*, uint8_t*, size_t)':
/home/c****/srvweb.cpp:20:15: error: 'last_temp' was not declared in this scope
J'ai encore pas mal de mal avec le C++ (promis je passe commande à mon libraire du meilleur bouquin pour débutant que vous me conseillerez) mais là je sèche vraiment.
struct SDATA {
float temp;
long tmillis;
// bool err; // les 2 bool pas encore utilisés
// bool valable;
};
extern SDATA last_temp; // dernière mesure
extern SDATA TabMesures[3600]; // toutes les mesures
Dans le fichier mesures.cpp
#include "mesures.h"
SDATA last_temp; // dernière mesure
SDATA TabMesures[3600]; // toutes les mesures
un #include dit au pré-processeur "copie à cet endroit tout le contenu du fichier dont je te donne le nom avant de compiler"
On ne fait pas d'allocation de mémoire dans un .h pour des variables sinon quand on inclut le .h dans deux fichiers différents on se retrouverait avec la variable en double lors de l'édition de liens
Dans le .h on fait des déclarations ➜ on explique au compilateur ce que sont les choses à connaître.
dans le .cpp on fait les définitions ➜ on crée les variables et le compilateur alloue un espace mémoire et généralement on met aussi l'implémentation des fonctions.
Donc j'ai intérêt à nettoyer mon code et à bien dissocier les déclarations (systématiquement dans le .h (sauf celles du .ino puisqu'il n'y a pas de .h) des définitions (dans les .cpp)
(une définition c'est à la fois la déclaration + réservation de la mémoire / création de la variable. C'est cela que vous ne voulez faire qu'une seule fois même si vous faites un #include du .h dans 30 .cpp ou .ino différents pour votre projet)
Les variables que l'on veut faire connaître au reste du code sont donc déclarées en extern dans le .h et réellement définies dans le .cpp
toto.h
#ifndef _TOTO_H_
#define _TOTO_H_
// les déclarations
extern int totoEntier;
extern double totoReel;
void initToto(int x, double y = 22); // pas besoin d'extern pour les fonctions. On met les valeurs par défaut dans le .h, pas le .cpp
#endif
et toto.cpp
#include "toto.h"
// les définitions
int totoEntier;
double totoReel;
// cette fonction n'étant pas dans le .h les autres fichiers ne peuvent pas l'utiliser
void fonctionCacheeNonConnueEnDehorsDeTotoCpp() {
totoEntier++;
}
// cette fonction est connue dans le .h donc fait partie de l'API de toto
void initToto(int x, double y) {
totoEntier = x;
totoReel = y;
fonctionCacheeNonConnueEnDehorsDeTotoCpp();
}