Ayrıca bakınız: C++ sürümü: C++‘da oneof/union tipleri nasıl işlenir
NanoPB, gömülü sistemler için kod boyutu açısından optimize edilmiş bir Protocol Buffers uygulamasıdır. Bu yazı, NanoPB ile C’de oneof (union) tiplerinin nasıl işleneceğini gösterir.
Proto tanımı
Önce oneof alanları içeren bir .proto dosyası oluşturun:
syntax = "proto3";
package example;
message OneofMessage {
oneof value {
uint32 int_value = 1;
float float_value = 2;
string string_value = 3;
}
}NanoPB kodu oluşturma
String arabellek boyutlarını belirtmek için bir .options dosyası ile NanoPB kodunu oluşturun:
oneof.options oluşturun:
example.OneofMessage.string_value max_size:32Ardından oluşturun:
protoc --nanopb_out=. oneof.protoBu, oneof.pb.h ve oneof.pb.c dosyalarını oluşturur.
C örneği
Oneof alanlarını işleyen tam bir C örneği:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "oneof.pb.h"
#include "pb_encode.h"
#include "pb_decode.h"
int main() {
// Kodlanmış mesaj için arabellek
uint8_t buffer[128];
size_t message_length;
// --- KODLAMA (int_value) ---
example_OneofMessage message = example_OneofMessage_init_zero;
// Oneof alanını ayarla (aynı anda yalnızca biri ayarlanabilir)
message.which_value = example_OneofMessage_int_value_tag;
message.value.int_value = 42;
// Kodlama için akış oluştur
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
// Mesajı kodla
if (!pb_encode(&ostream, example_OneofMessage_fields, &message)) {
printf("Encoding failed: %s\n", PB_GET_ERROR(&ostream));
return 1;
}
message_length = ostream.bytes_written;
printf("Encoded %zu bytes (int_value)\n", message_length);
// Hex dökümünü yazdır
printf("Encoded data: ");
for (size_t i = 0; i < message_length; i++) {
printf("%02x ", buffer[i]);
}
printf("\n");
// --- KOD ÇÖZME ---
example_OneofMessage decoded = example_OneofMessage_init_zero;
// Kod çözme için akış oluştur
pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
// Mesajın kodunu çöz
if (!pb_decode(&istream, example_OneofMessage_fields, &decoded)) {
printf("Decoding failed: %s\n", PB_GET_ERROR(&istream));
return 1;
}
// Kodu çözülen değeri yazdır
printf("Decoded value:\n");
switch (decoded.which_value) {
case example_OneofMessage_int_value_tag:
printf(" int_value: %u\n", (unsigned int)decoded.value.int_value);
break;
case example_OneofMessage_float_value_tag:
printf(" float_value: %f\n", decoded.value.float_value);
break;
case example_OneofMessage_string_value_tag:
printf(" string_value: %s\n", decoded.value.string_value);
break;
default:
printf(" (none)\n");
break;
}
return 0;
}Derleme komutu
Örneği nanopb ile derleyin. NanoPB genellikle kaynak dosyaları doğrudan projenize dahil edilerek kullanılır:
gcc -o oneof_example oneof_example.c oneof.pb.c pb_common.c pb_encode.c pb_decode.c -I.Not: NanoPB kaynak dosyaları (pb_common.c, pb_encode.c, pb_decode.c) projenizle birlikte doğrudan derlenmelidir. Bunları NanoPB GitHub deposundan edinebilirsiniz.
Python test betiği
Kodlamayı doğrulamak için Python’un protobuf kütüphanesini kullanabilirsiniz:
import oneof_pb2
# İkili veriyi oku
with open('encoded.bin', 'rb') as f:
data = f.read()
# Kod çöz
msg = oneof_pb2.OneofMessage()
msg.ParseFromString(data)
print("Python decoded values:")
print(f" Which oneof: {msg.WhichOneof('value')}")
if msg.HasField('int_value'):
print(f" int_value: {msg.int_value}")
if msg.HasField('float_value'):
print(f" float_value: {msg.float_value}")
if msg.HasField('string_value'):
print(f" string_value: {msg.string_value}")Önce Python protobuf tanımlarını derleyin:
protoc --python_out=. oneof.protoArdından C örneğini, kodlanmış veriyi bir dosyaya kaydedecek şekilde değiştirin:
// Kodlamadan sonra bunu ekleyin:
FILE *f = fopen("encoded.bin", "wb");
fwrite(buffer, 1, message_length, f);
fclose(f);Tüm oneof tipleriyle örnek
Tüm oneof tiplerini gösteren bir örnek:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "oneof.pb.h"
#include "pb_encode.h"
#include "pb_decode.h"
void encode_decode_int_value() {
uint8_t buffer[128];
size_t message_length;
example_OneofMessage message = example_OneofMessage_init_zero;
message.which_value = example_OneofMessage_int_value_tag;
message.value.int_value = 42;
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if (!pb_encode(&ostream, example_OneofMessage_fields, &message)) {
printf("Encoding failed\n");
return;
}
message_length = ostream.bytes_written;
example_OneofMessage decoded = example_OneofMessage_init_zero;
pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
if (!pb_decode(&istream, example_OneofMessage_fields, &decoded)) {
printf("Decoding failed\n");
return;
}
printf("int_value: %u\n", (unsigned int)decoded.value.int_value);
}
void encode_decode_float_value() {
uint8_t buffer[128];
size_t message_length;
example_OneofMessage message = example_OneofMessage_init_zero;
message.which_value = example_OneofMessage_float_value_tag;
message.value.float_value = 3.14159f;
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if (!pb_encode(&ostream, example_OneofMessage_fields, &message)) {
printf("Encoding failed\n");
return;
}
message_length = ostream.bytes_written;
example_OneofMessage decoded = example_OneofMessage_init_zero;
pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
if (!pb_decode(&istream, example_OneofMessage_fields, &decoded)) {
printf("Decoding failed\n");
return;
}
printf("float_value: %f\n", decoded.value.float_value);
}
void encode_decode_string_value() {
uint8_t buffer[128];
size_t message_length;
example_OneofMessage message = example_OneofMessage_init_zero;
message.which_value = example_OneofMessage_string_value_tag;
strncpy(message.value.string_value, "Hello", sizeof(message.value.string_value) - 1);
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if (!pb_encode(&ostream, example_OneofMessage_fields, &message)) {
printf("Encoding failed\n");
return;
}
message_length = ostream.bytes_written;
example_OneofMessage decoded = example_OneofMessage_init_zero;
pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
if (!pb_decode(&istream, example_OneofMessage_fields, &decoded)) {
printf("Decoding failed\n");
return;
}
printf("string_value: %s\n", decoded.value.string_value);
}
int main() {
printf("Testing all oneof types:\n");
encode_decode_int_value();
encode_decode_float_value();
encode_decode_string_value();
return 0;
}Önemli noktalar
- Oneof tanımı: Union tiplerini tanımlamak için proto’da
oneofanahtar kelimesini kullanın - Oluşturulan which_field: NanoPB, hangi alanın ayarlandığını izlemek için
which_fieldnameenum’u oluşturur - Kodlama:
which_*değerini uygun etikete ayarlayın, ardından alan değerini ayarlayın - Kod çözme: Hangi alanın ayarlandığını belirlemek için
which_*değerini kontrol edin - Karşılıklı dışlama: Bir oneof’ta aynı anda yalnızca bir alan ayarlanabilir
- Union semantiği: C union’larına benzer ancak tip güvenlidir
- Bellek verimliliği: Yalnızca bir alan için bellek ayrılır
Oneof ne zaman kullanılır
- Birkaç olası değerden yalnızca birinin bulunması gerektiğinde
- Tüm alanlar için yer ayırmayarak bellekten tasarruf etmek istediğinizde
- Tip güvenli union’lara ihtiyaç duyduğunuzda
- Variant tipleri veya etiketli union’ları temsil ederken
- Polimorfik mesajlar uygularken
Beklenen çıktı
Encoded 2 bytes (int_value)
Encoded data: 08 2a
Decoded value:
int_value: 42Beklenen çıktı (tüm tipler)
Testing all oneof types:
int_value: 42
float_value: 3.141590
string_value: HelloC++‘dan farkları
C sürümü, C++ sürümüyle neredeyse aynıdır:
- C’de printf format belirteçleri için açık cast kullanın
- Oneof işleme için C++‘a özgü özellikler gerekmez
- Oluşturulan kod her iki dil için de aynıdır
- Bellek yönetimi aynıdır (her iki durumda da statik tahsis)
Diğer NanoPB yazıları
- C++‘da temel skaler tipler
- C’de temel skaler tipler
- C++‘da string tipleri
- C’de string tipleri
- C++‘da bytes tipleri
- C’de bytes tipleri
- C++‘da opsiyonel alanlar
- C’de opsiyonel alanlar
- C++‘da tekrarlanan alanlar/diziler
- C’de tekrarlanan alanlar/diziler
- C++‘da enum’lar
- C’de enum’lar
- C++‘da iç içe mesajlar
- C’de iç içe mesajlar
- C++‘da Oneof/union tipleri
- C++‘da özel dizi dönüştürücüler
- C’de özel dizi dönüştürücüler