NanoPB : Comment gérer les types scalaires de base en C
Voir aussi : Version C++ : Comment gérer les types scalaires de base 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 scalaires de base (entiers, flottants, booléens) en C avec NanoPB.
Définition proto
Créez d’abord un fichier .proto simple avec des types scalaires de base :
syntax = "proto3";
package example;
message ScalarMessage {
uint32 uint32_value = 1;
uint64 uint64_value = 2;
int32 int32_value = 3;
int64 int64_value = 4;
float float_value = 5;
bool bool_value = 6;
}Générer le code NanoPB
Générez le code C NanoPB en utilisant le générateur nanopb :
protoc --nanopb_out=. scalars.protoCela générera scalars.pb.h et scalars.pb.c.
Exemple en C
Voici un exemple complet en C qui encode et décode le message :
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "scalars.pb.h"
#include "pb_encode.h"
#include "pb_decode.h"
int main() {
// Tampon pour le message encodé
uint8_t buffer[128];
size_t message_length;
// --- ENCODAGE ---
example_ScalarMessage message = example_ScalarMessage_init_zero;
// Définir les valeurs des champs
message.uint32_value = 42;
message.uint64_value = 1234567890ULL;
message.int32_value = -100;
message.int64_value = -9876543210LL;
message.float_value = 3.14159f;
message.bool_value = true;
// Créer un flux pour l'encodage
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
// Encoder le message
if (!pb_encode(&ostream, example_ScalarMessage_fields, &message)) {
printf("Encoding failed: %s\n", PB_GET_ERROR(&ostream));
return 1;
}
message_length = ostream.bytes_written;
printf("Encoded %zu bytes\n", message_length);
// Afficher le dump hexadécimal des données encodées
printf("Encoded data: ");
for (size_t i = 0; i < message_length; i++) {
printf("%02x ", buffer[i]);
}
printf("\n");
// --- DÉCODAGE ---
example_ScalarMessage decoded = example_ScalarMessage_init_zero;
// Créer un 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_ScalarMessage_fields, &decoded)) {
printf("Decoding failed: %s\n", PB_GET_ERROR(&istream));
return 1;
}
// Afficher les valeurs décodées
printf("Decoded values:\n");
printf(" uint32_value: %u\n", (unsigned int)decoded.uint32_value);
printf(" uint64_value: %llu\n", (unsigned long long)decoded.uint64_value);
printf(" int32_value: %d\n", decoded.int32_value);
printf(" int64_value: %lld\n", (long long)decoded.int64_value);
printf(" float_value: %f\n", decoded.float_value);
printf(" bool_value: %s\n", decoded.bool_value ? "true" : "false");
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 :
gcc -o scalars_example scalars_example.c scalars.pb.c pb_common.c pb_encode.c pb_decode.c -I.Remarque : 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 NanoPB.
Script de test Python
Pour vérifier l’encodage, vous pouvez utiliser la bibliothèque protobuf de Python :
import scalars_pb2
# Lire les données binaires
with open('encoded.bin', 'rb') as f:
data = f.read()
# Décoder
msg = scalars_pb2.ScalarMessage()
msg.ParseFromString(data)
print("Python decoded values:")
print(f" uint32_value: {msg.uint32_value}")
print(f" uint64_value: {msg.uint64_value}")
print(f" int32_value: {msg.int32_value}")
print(f" int64_value: {msg.int64_value}")
print(f" float_value: {msg.float_value}")
print(f" bool_value: {msg.bool_value}")Compilez d’abord les définitions protobuf Python :
protoc --python_out=. scalars.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);Points clés
- Utilisez
*_init_zeropour initialiser les messages avec les valeurs par défaut pb_ostream_from_buffercrée un flux de sortie pour l’encodagepb_istream_from_buffercrée un flux d’entrée pour le décodagepb_encodeetpb_decodegèrent l’encodage/décodage effectif- Vérifiez les valeurs de retour et utilisez
PB_GET_ERRORpour la gestion des erreurs - En C, utilisez des conversions explicites pour les spécificateurs de format printf avec les entiers 64 bits
Sortie attendue
Encoded 28 bytes
Encoded data: 08 2a 10 d2 95 89 04 18 9c ff ff ff ff ff ff ff 01 20 c6 ef be ad de 05 2d 15 49 0e 40 30 01
Decoded values:
uint32_value: 42
uint64_value: 1234567890
int32_value: -100
int64_value: -9876543210
float_value: 3.141590
bool_value: trueDifférences par rapport au C++
La version C est presque identique à la version C++, avec seulement des différences mineures :
- Utilisez
#include <stdint.h>pour les types d’entiers de largeur fixe - Utilisez des conversions explicites pour les spécificateurs de format printf
- Aucune fonctionnalité spécifique au C++ n’est nécessaire (le code généré est le même)
Plus 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++
- 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 tableau personnalisés en C++
- Convertisseurs de tableau personnalisés en C