sizeof d'un tableau de byte faux dans une fonction

Bonjour

Je débute avec Arduino, et je souhaite créer une fonction "debug" qui me permette d'afficher le contenu d'un tableau de byte de façon lisible dans la console (Serial).
Exemple: 90, E6, BA, BC, 99, 2A

Pour tester, je déclare un tableau de taille 6, et quand je fais un sizeof dessus ça me retourne bien 6.
Maintenant quand je passe ce tableau à une fonction, et que que je fais un sizeof sur le paramètre, ça m'affiche 2 :

byte monTableau[] = { 0x90, 0xE6, 0xBA, 0xBC, 0x99, 0x2A };

void setup() {
  Serial.begin(9600);
  Serial.println(sizeof(monTableau)); // affiche 6
  debug(monTableau);
}

void loop() {
  
}

// Ma fonction pour afficher un tableau :
void debug(byte* data){
  Serial.println(sizeof(data)); // affiche 2, WTF ?
  for(int i=0; i<sizeof(data); i++){
    if(i>0){
      Serial.print(", ");
    }
    Serial.print(data[i], HEX);
  }
  Serial.println("");
}

J'ai cherché un peu, et j'ai vu que sizeof était évalué au moment de la compilation, et pas de l’exécution, du coup il me retourne la taille du pointeur (2), et pas celle du tableau :astonished:.

Est-ce qu'il y a un moyen pour calculer la taille du tableau passé en paramètre de ma fonction debug ?
Sinon il me reste plus qu'à ajouter un paramètre size à ma fonction, mais ça sera moins pratique à utiliser...

Merci

Bonjour,

Galdon:
J'ai cherché un peu, et j'ai vu que sizeof était évalué au moment de la compilation, et pas de l’exécution, du coup il me retourne la taille du pointeur (2), et pas celle du tableau :astonished:.

sizeof est une instruction évalué uniquement à la compilation.
La valeur de sizeof est remplacé par la taille statique de l'objet passé en argument.
Faire une sizeof sur quelque chose de dynamique donnera uniquement la taille du pointeur qui lui correspond.

Galdon:
Est-ce qu'il y a un moyen pour calculer la taille du tableau passé en paramètre de ma fonction debug ?
Sinon il me reste plus qu'à ajouter un paramètre size à ma fonction, mais ça sera moins pratique à utiliser...

Réponse bête et méchante : NON.
En c/c++ il n'y as pas de gestion des buffer overflow (enfin si dans certain cas, mais pas ici) comme c'est le cas dans certain autre langage (python, java, ...).
Il n'y a donc pas de moyen de savoir combien fait un tableau en taille (chaine de caractéres exclu, puisse qu'elle sont censé se finir par \0).

De même c'est une des raisons qui fait que :

byte t[5];
t[10] = 42;

Ne génère pas d'erreur lors de la compilation, mais fait n'importe quoi lors de l'exécution.
(Dans ce cas précis ou t[10] est demandé implicitement il y aurait eu un warning, mais si t[10] avait était remplacé par t[a] avec a=10 il n'y aurait pas eu de warning)

Ok, merci beaucoup pour cette réponse claire & complète.

Bonjour,

Sauf erreur de ma part, tu dois pouvoir faire ça

Serial.println(sizeof(data)); // affiche 2, WTF ?
Serial.println(sizeof(&data)); // affiche 6, normalement ?

le & permet de cibler la variable pointée par le pointeur.

A tester

Non

si data est déclaré comme dans le code ci-dessus :

void debug(byte* data)

data est donc une variable pointeur sur octet.

Alors:
sizeof( data ) = taille d'un pointeur = 2 sur Arduino
sizeof( &data ) = taille d'un pointeur sur un pointeur = taille d'un pointeur = toujours 2
sizeof( *data ) = taille de 1 élement du type pointé par un pointeur = sizeof (byte) = 1

Le seul moyen de faire une fonction générique d'affichage comme le demande Galdon est de passer la taille à l'exécution.
Par exemple :

void debug(byte* data, size_t len)

A utiliser par
Soit :

char Tableau[15];
debug( Tableau, sizeof(Tableau) );

Soit :

#define DATA_SIZE 15
char *Tableau= malloc( DATA_SIZE );
debug( Tableau, DATA_SIZE ); // car sizeof(Tableau)==2 et sizeof(*Tableau)==1

Éventuellement si on sait qu'il s'agit d'une chaîne de caractères terminée par un caractère nul '\0' on peu utiliser strlen().

Mais en C/C++, dès qu'on passe par des pointeurs on ne sait plus combien d'objets sont pointés.

barbudor:

#define DATA_SIZE  15

char *Tableau= malloc( DATA_SIZE );
debug( Tableau, DATA_SIZE );  // car sizeof(Tableau)==2 et sizeof(*Tableau)==1

Ne pas oublier de libérer la mémoire après :wink:

free(Tableau);

OK. :roll_eyes:
Au temps pour moi.

barbudor:

#define DATA_SIZE 15
char *Tableau= malloc( DATA_SIZE );
debug( Tableau, DATA_SIZE ); // car sizeof(Tableau)==2 et sizeof(*Tableau)==1

Éventuellement si on sait qu'il s'agit d'une chaîne de caractères terminée par un caractère nul '\0' on peu utiliser strlen().

Il faut éviter au maximum de faire des malloc() quand on a que 2Ko de RAM ... un malloc ça passe, deux malloc sa fragmente, trois malloc tu sait plus ou tu en est ...
Quitte à allouer une taille fixe de char autant faire une variable "normal" telle que : char Tableau[DATA_SIZE] ...

Sinon il reste la solution de la macro pré-processeur ?
Genre :

#define debug(data) { \
  Serial.println(sizeof(data)); \
  for(uint8_t i=0; i < sizeof(data); ++i) { \
    if(i) Serial.print(", "); \
    Serial.print(data[i], HEX); \
  } \
  Serial.println(); \
}

Par contre ça va ajouter du code à chaque fois que debug(...) sera utilisé, dans certain cas ça peut rendre le code hyper lourd une fois compilé.
Mais il y un gros avantage, une fois la phase de debug finit il suffit de faire #define debug(data) {} et hop ! Plus rien !