Joli bug avec "byte"

Bonjour,

Je viens encore de trouver un problème que je ne comprend pas. Il est dit que pour un entier non signé 8 bits sur Arduino, on peut utiliser uint8_t, byte, unsigned char. Je m’intéresse au deuxièma car c’est plus court à écrire, le premier me fait penser aux mots de passes avec une lettre un symbole et un chiffre…

byte est défini dans Arduino.h, ligne 127 pour la version 1.8.12 comme suit:
typedef uint8_t byte;

J’ai écrit un programme qui ne fait rien, et je l’ai découpé en trois morceaux:

lib.h

byte vide(byte nul);

lib.cpp

#include "lib.h"
#include <Arduino.h>

byte vide(byte nul)
{
  return nul+1;
}

Bug.ino

#include "lib.h"
#include <Arduino.h>

void setup()
{
  vide(0);
}

void loop()
{
}

et quand je compile, le compilateur m’insulte méchamment:

Arduino : 1.8.12 (Windows 10), Carte : "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

In file included from I:\Bug\Bug.ino:1:0:

lib.h:1:1: error: 'byte' does not name a type; did you mean 'bit'?

 byte vide(byte nul);

 ^~~~

 bit

In file included from sketch\lib.cpp:1:0:

lib.h:1:1: error: 'byte' does not name a type; did you mean 'bit'?

 byte vide(byte nul);

 ^~~~

 bit

I:\Bug\Bug.ino: In function 'void setup()':

Bug:6:3: error: 'vide' was not declared in this scope

   vide(0);

   ^~~~

I:\Bug\Bug.ino:6:3: note: suggested alternative: 'void'

   vide(0);

   ^~~~

   void

exit status 1
'byte' does not name a type; did you mean 'bit'?

Ce rapport pourrait être plus détaillé avec
l'option "Afficher les résultats détaillés de la compilation"
activée dans Fichier -> Préférences.

J’ai cherché un moment, j’ai trouvé ça sur un plus gros programme. Je sais ce qu’il faut faire: supprimer l’appel à Arduino.h qui est inclus automatiquement je pense ou bien inverser les deux premières lignes. Mais je vais retrouver ce comportement avec d’autres bibliothèques.

Ma question est pourquoi il me dit que byte n’est pas défini?

Si lib.h était inclus après Arduino.h cela irait mieux.

On inclut toujours les .h système avant les .h applicatifs.

Si lib.h était inclus après Arduino.h cela irait mieux.

ou bien inverser les deux premières lignes.

Si on inverse effectivement cela passe comme signalé.

Mais dans l’avenir, avec ma chance j’aurais de bibliothèques persos qui seront dans le mauvais ordre.

Parce qu’a priori Arduino.h étant mis obligatoirement, elle doit être mise avant. et le fait de la remettre après ne devrait pas avoir d’effet à cause de la directive
#ifndef Arduino_h

A moins que le compilateur voyant passer le #include <Arduino.h> la retire pour la mettre après.

Le préprocesseur, pas le compilateur.

Il évalue dans l'ordre d'inclusion.

Ce n’est pas le compilateur, mais l’ide arduino qui ajoute le #include <Arduino.h>
Il est tout à fait possible que voyant que Arduino.h est déjà inclus explicitement, l’ide ne l’inclue pas.
Ça peut se vérifier sur le .cpp généré. Comme je suis sur ma tablette je ne peux pas le vérifier actuellement.

Merci.

Il est ou ce cpp?

Il faut activer le détail de la compilation dans préférences et tu as la ligne de commande du compilateur avec le chemin du fichier.

kamill:
Ce n’est pas le compilateur, mais l’ide arduino qui ajoute le #include <Arduino.h>
Il est tout à fait possible que voyant que Arduino.h est déjà inclus explicitement, l’ide ne l’inclue pas.
Ça peut se vérifier sur le .cpp généré. Comme je suis sur ma tablette je ne peux pas le vérifier actuellement.

Oui pour les .ino
Pour les .cpp il faut inclure Arduino.h explicitement.

Après avpir vu quelques lignes dont deux longues comme un jour de confinement (longue de 1500 caractères!), voici le contenu du cpp:

#include <Arduino.h>
#line 1 "I:\\Bug\\Bug.ino"
#include "lib.h"
#include <arduino.h>

#line 4 "I:\\Bug\\Bug.ino"
void setup();
#line 9 "I:\\Bug\\Bug.ino"
void loop();
#line 4 "I:\\Bug\\Bug.ino"
void setup()
{
  vide(0);
}

void loop()
{
}

et le Bug.ino.cpp.d

C:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_500562\sketch\Bug.ino.cpp.o: \
 C:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_500562\sketch\Bug.ino.cpp \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/Arduino.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/binary.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/WCharacter.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/WString.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/HardwareSerial.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/Stream.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/Print.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/Printable.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/USBAPI.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/Arduino.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\variants\mega/pins_arduino.h \
 C:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_500562\sketch\lib.h \
 C:\Users\Utilisateur\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2\cores\arduino/arduino.h

Mais j'avoue franchement que cela ne me parle pas trop

hbachetti:
Oui pour les .ino
Pour les .cpp il faut inclure Arduino.h explicitement.

On parlait bien d'un fichier .ino

Dans le .ino Arduino.h est inutile.

Si lib.h (qui utilise le type byte) est inclus dans lib?cpp avant Arduino.h, lors de la compilation de lib.cpp au moment où la ligne byte vide(byte nul) est compilée byte n'est pas connu. byte sera connu ensuite, lors de l'inclusion de Arduino.h, mais c'est trop tard.

Oui, c’est pour cela qu’on se pose la question si Arduino.h n’est pas enlevé parce qu’il apparait ensuite. Mais d’après ce que je comprend du cpp:
#include <Arduino.h> -------> il est d’abord rajouté ici
#line 1 “I:\Bug\Bug.ino”
#include “lib.h” ---------> lib vient ensuite
#include <arduino.h> ------> la il le rajoute encore mais cela ne doit pas avoir d’effet (#ifndef Arduino_h → défini)
#line 4 “I:\Bug\Bug.ino”

Il faut voir le préprocesseur comme un outil qui fait de la substitution au fil de l'eau.

Il lit le fichier lib.cpp, voit qu'il inclut un fichier lib.h, il lit donc lib.h, qui utilise un type byte qui est inconnu à cet instant T.
il ne faut pas confondre un préprocesseur avec un linker qui fait plusieurs passes pour résoudre les symboles.

Le préprocesseur ne fait qu'une passe. Ce n'est pas parce que byte va être connu plus tard quand il inclura Arduino.h qu'il va se dire "Ah OK, maintenant je sais ce que veut dire le byte que j'ai vu avant dans lib.h".
Non, le préprocesseur ne cherche pas à comprendre, il signale une erreur, peu importe la suite.

Je suis d'accord; mais dans le cas présent, il a mis Arduino.h avant

Ce n’est pas ce que je vois.

vileroi:
lib.cpp

#include "lib.h"

#include <Arduino.h>

byte vide(byte nul)
{
 return nul+1;
}

Je viens de vérifier.
Si Arduino.h n’est pas inclus explicitement, l’ide mets #include <Arduino.h> en tête du fichier .cpp
Si Arduino.h est inclus explicitement, l’ide ne mets pas l’#include <Arduino.h>. Donc erreur si on le met après son utilisation dans le programme.

.cpp sans #include explicite

#include <Arduino.h>
#line 1 "D:\\Users\\Patrick\\Documents\\Arduino\\sketch_apr25e\\sketch_apr25e.ino"
#include "lib.h"
//#include <Arduino.h>

#line 4 "D:\\Users\\Patrick\\Documents\\Arduino\\sketch_apr25e\\sketch_apr25e.ino"
void setup();
#line 9 "D:\\Users\\Patrick\\Documents\\Arduino\\sketch_apr25e\\sketch_apr25e.ino"
void loop();
#line 4 "D:\\Users\\Patrick\\Documents\\Arduino\\sketch_apr25e\\sketch_apr25e.ino"
void setup()
{
  Serial.begin(115200);
}

void loop()
{
}

.cpp avec #include explicite → pas de #include <Arduino.h> en première ligne

#line 1 "D:\\Users\\Patrick\\Documents\\Arduino\\sketch_apr25e\\sketch_apr25e.ino"
#include "lib.h"
#include <Arduino.h>

#line 4 "D:\\Users\\Patrick\\Documents\\Arduino\\sketch_apr25e\\sketch_apr25e.ino"
void setup();
#line 9 "D:\\Users\\Patrick\\Documents\\Arduino\\sketch_apr25e\\sketch_apr25e.ino"
void loop();
#line 4 "D:\\Users\\Patrick\\Documents\\Arduino\\sketch_apr25e\\sketch_apr25e.ino"
void setup()
{
  Serial.begin(115200);
}

void loop()
{
}

On est en train de confondre deux choses : la compilation du ou des sketches (il peut y en avoir plusieurs) et la compilation des .cpp.

Oui l'IDE concatène les .ino en 1 seul fichier et génère un .ino.cpp
Il ajoute également Arduino.h et les prototypes de fonctions de tous les .ino au début du fichier.

Je ne parle pas de ce fichier généré.

Je parle du fichier lib.cpp (voir premier post).
Les fichiers .cpp présents dans le projet ne sont pas du tout traités comme les .ino
L'IDE les compile, et ne fait rien d'autre.
Arduino.h n'est pas ajouté automatiquement aux .cpp du projet.

Chaque fichier .cpp est compilé séparément.

Dans son premier post vileroi parles bien de la compilation du fichier .ino

In file included from I:\Bug\Bug.ino:1:0:

lib.h:1:1: error: 'byte' does not name a type; did you mean 'bit'?

Après je suis d'accord avec toi

  • le fichier Arduino.h est inclus par l'ide dans le .ino, donc inutile de l'inclure, au mieux ça ne sert à rien, au pire ça met le souk comme dans l'example
  • Arduino.h doit être inclus explicitement dans le .cpp, s'il l'utilise. Il doit être placé avant les instructions, définitions, déclarations ... qui l'utilise.