NanoPB: Gérer les enums en C++
Voir aussi : Version C : Comment gérer les enums en C
NanoPB est une implémentation de Protocol Buffers optimisée pour la taille du code, destinée aux systèmes embarqués. Cet article montre comment gérer les types enum en C++ avec NanoPB.
Définition Proto
Créez d’abord un fichier .proto avec des enums :
syntax = "proto3";
package example;
enum Status {
UNKNOWN = 0;
OK = 1;
ERROR = 2;
BUSY = 3;
}
message EnumMessage {
Status status = 1;
}Génération du code NanoPB
Générez le code NanoPB :
protoc --nanopb_out=. enums.protoCela générera enums.pb.h et enums.pb.c.
Exemple C++
Voici un exemple C++ complet gérant les enums :
#include <stdio.h>
#include "enums.pb.h"
#include "pb_encode.h"
#include "pb_decode.h"
// Fonction utilitaire pour convertir un enum en chaîne
const char* status_to_string(example_Status status) {
switch (status) {
case example_Status_UNKNOWN: return "UNKNOWN";
case example_Status_OK: return "OK";
case example_Status_ERROR: return "ERROR";
case example_Status_BUSY: return "BUSY";
default: return "INVALID";
}
}
int main() {
// Tampon pour le message encodé
uint8_t buffer[64];
size_t message_length;
// --- ENCODAGE ---
example_EnumMessage message = example_EnumMessage_init_zero;
// Définir la valeur de l'enum
message.status = example_Status_OK;
// Créer le flux pour l'encodage
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
// Encoder le message
if (!pb_encode(&ostream, example_EnumMessage_fields, &message)) {
printf("Échec de l'encodage : %s\n", PB_GET_ERROR(&ostream));
return 1;
}
message_length = ostream.bytes_written;
printf("Encodé %zu octets\n", message_length);
// Afficher le dump hexadécimal des données encodées
printf("Données encodées : ");
for (size_t i = 0; i < message_length; i++) {
printf("%02x ", buffer[i]);
}
printf("\n");
// --- DÉCODAGE ---
example_EnumMessage decoded = example_EnumMessage_init_zero;
// Créer le flux pour le décodage
pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
// Décoder le message
if (!pb_decode(&istream, example_EnumMessage_fields, &decoded)) {
printf("Échec du décodage : %s\n", PB_GET_ERROR(&istream));
return 1;
}
// Afficher la valeur décodée
printf("Valeur décodée :\n");
printf(" status : %s (valeur enum : %d)\n",
status_to_string(decoded.status), decoded.status);
return 0;
}Commande de compilation
Compilez l’exemple avec nanopb. NanoPB est généralement utilisé en incluant directement les fichiers sources dans votre projet :
g++ -o enums_example enums_example.cpp enums.pb.c pb_common.c pb_encode.c pb_decode.c -I.Note : Les fichiers sources NanoPB (pb_common.c, pb_encode.c, pb_decode.c) doivent être compilés directement avec votre projet. Vous pouvez les obtenir depuis le dépôt GitHub de NanoPB.
Script de test Python
Pour vérifier l’encodage, vous pouvez utiliser la bibliothèque protobuf de Python :
import enums_pb2
# Lire les données binaires
with open('encoded.bin', 'rb') as f:
data = f.read()
# Décoder
msg = enums_pb2.EnumMessage()
msg.ParseFromString(data)
print("Valeurs décodées par Python :")
print(f" status : {enums_pb2.Status.Name(msg.status)}")D’abord, compilez les définitions protobuf Python :
protoc --python_out=. enums.protoModifiez ensuite l’exemple C++ pour enregistrer les données encodées dans un fichier :
// Après l'encodage, ajoutez ceci :
FILE *f = fopen("encoded.bin", "wb");
fwrite(buffer, 1, message_length, f);
fclose(f);Exemple avec enum dans une instruction switch
Voici un exemple montrant comment utiliser les enums dans des instructions switch :
#include <stdio.h>
#include "enums.pb.h"
#include "pb_encode.h"
#include "pb_decode.h"
void handle_status(example_Status status) {
printf("Traitement du status : ");
switch (status) {
case example_Status_UNKNOWN:
printf("UNKNOWN - État par défaut\n");
break;
case example_Status_OK:
printf("OK - Opération réussie\n");
break;
case example_Status_ERROR:
printf("ERROR - Opération échouée\n");
break;
case example_Status_BUSY:
printf("BUSY - Système occupé\n");
break;
default:
printf("INVALID - Valeur enum inconnue\n");
break;
}
}
int main() {
uint8_t buffer[64];
size_t message_length;
// Tester toutes les valeurs de l'enum
example_Status test_values[] = {
example_Status_UNKNOWN,
example_Status_OK,
example_Status_ERROR,
example_Status_BUSY
};
for (size_t i = 0; i < 4; i++) {
example_EnumMessage message = example_EnumMessage_init_zero;
message.status = test_values[i];
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if (!pb_encode(&ostream, example_EnumMessage_fields, &message)) {
printf("Échec de l'encodage : %s\n", PB_GET_ERROR(&ostream));
return 1;
}
message_length = ostream.bytes_written;
example_EnumMessage decoded = example_EnumMessage_init_zero;
pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
if (!pb_decode(&istream, example_EnumMessage_fields, &decoded)) {
printf("Échec du décodage : %s\n", PB_GET_ERROR(&istream));
return 1;
}
handle_status(decoded.status);
}
return 0;
}Points clés
- Définition d’enum : Définissez les enums dans le fichier
.protoavec des valeurs explicites - Types générés : NanoPB génère des types enum avec la nomenclature
package_EnumName - Encodage : Affectez directement la valeur de l’enum au champ
- Décodage : Les valeurs enum sont décodées automatiquement
- Valeurs par défaut : La première valeur de l’enum (généralement 0) est la valeur par défaut
- Instructions switch : Les enums fonctionnent naturellement dans les instructions switch
- Sécurité de type : Les enums fournissent une sécurité de type par rapport aux entiers bruts
- Valeurs inconnues : Les valeurs enum invalides peuvent être décodées comme leur valeur numérique
Quand utiliser les enums
- Quand vous avez un ensemble fixe de valeurs possibles
- Quand vous voulez une sécurité de type pour les champs d’état ou de mode
- Quand vous voulez un code auto-documenté
- Quand vous avez besoin de distinguer différents modes de fonctionnement
- Quand vous voulez encoder une signification sémantique dans les messages
Sortie attendue
Encoded 2 bytes
Encoded data: 08 01
Decoded value:
status: OK (enum value: 1)Sortie attendue (exemple switch)
Handling status: UNKNOWN - Default state
Handling status: OK - Operation successful
Handling status: ERROR - Operation failed
Handling status: BUSY - System busyPlus d’articles sur NanoPB
- Types scalaires de base en C++
- Types scalaires de base en C
- Types chaîne en C++
- Types chaîne en C
- Types bytes en C++
- Types bytes en C
- Champs optionnels en C++
- Champs optionnels en C
- Champs répétés/tableaux en C++
- Champs répétés/tableaux en C
- Enums en C
- Messages imbriqués en C++
- Messages imbriqués en C
- Types oneof/union en C++
- Types oneof/union en C
- Convertisseurs de tableaux personnalisés en C++
- Convertisseurs de tableaux personnalisés en C