Google Protocol Buffers have become a very popular serialization mechanism for simple to complex/variant data structures. Due to the variation of message formats in a given protocol, the presence and/or lack of fields on an ad-hoc basis makes implementation in the C language somewhat of a challenge.
Three Protocol Buffers Libraries for C
Thanks to the open-source world, a couple of valid options exist, but choosing the right one depends on the complexity of the protocol and memory/performance requirements.
Google Protocol Buffers for C++
The obvious first choice may seem to go right to the source. Google’s Protocol Buffer Compiler supports the generation of a C++ protocol implementation from a .proto specification. Though you are developing in C, and your complier supports C++, you could use the C++ API directly from C, or at least create a C wrapper for the target protocol.
- Pros: Formally supported by Google, bleeding edge
- Cons: Well, it’s C++ and does lots of dynamic memory allocation
protobuf-c is a pretty solid and full implementation of protocol buffers completely in C. It provides the protobuf-c library for interfacing with an arbitrary generated protocol. It also provides protoc-c, which is an extension to the Google Protocol Buffer compiler for generating C protocol source code from a standard .proto specification.
- Pros: Full C implementation, configurable memory usage
- Cons: Provides structural meta-data, but tree iteration is painful; doesn’t yet support v2.6.0
If you have very strict memory constraints or maybe don’t have the luxury of dynamic-memory allocation, the you might consider using protobuf-embedded-c. It was written specifically for memory constrained (tiny) systems, and is generated into a monolithic library for a given protocol.
- Pros: Geared for static memory allocation, simpler API, monolithic library
- Cons: Doesn’t support message nesting
What Does Protocol Buffers v2.6.0 add?
Google recently released version 2.6.0 of the specification, which adds a formal concept for a union type they refer to as a oneof element. This creates a formal way to say a thing is either A or B, but not both. This allows formal polymorphic types in a protocol specification. It also means a smaller maximum memory footprint and less hassle
Additionally, v2.6.0 introduced a formal deprecation method for protocol elements. A decent level of deprecation has existed for a long time, which basically allows new elements added to a protocol to be added, without breaking the API. The receiver of the protocol buffer simply discards unsupported fields. The main problem with this is that protocol elements at a given level must always use a new ID, and old IDs cannot be reused, which can be annoying. In v2.6.0, elements can be formally deprecated, thus alleviating backwards compatibility pains.