C Guide¶
This document will introduce how to use bitproto with C language.
Compile bitproto for C¶
Firstly, run the bitproto compiler to generate code for C:
$ bitproto c pen.bitproto
Where the pen.bitproto
is introduced in earlier section An example bitproto.
We will find that bitproto generates us two files in current directory:
pen_bp.h
: Contains the declarations of structs, macros and api functions etc.pen_bp.c
: Contains the function implementations.
It’s recommended to open this two generated files to have a look. In the generated file pen_bp.h
:
The
enum Color
in bitproto is mapped to atypedef
statement in C, and the enum values are mapped to macros:typedef uint8_t Color; // 3bit #define COLOR_UNKNOWN 0 #define COLOR_RED 1 #define COLOR_BLUE 2 #define COLOR_GREEN 3
The
Timestamp
type in bitproto is mapped to atypedef
in C:typedef int64_t Timestamp; // 64bit
The message
Pen
in bitproto is mapped to astruct
in C:struct Pen { Color color; // 3bit Timestamp produced_at; // 64bit };
The compiler also generates three functions, they are the encoder, decoder and json formatter.
int EncodePen(struct Pen *m, unsigned char *s); int DecodePen(struct Pen *m, unsigned char *s); int JsonPen(struct Pen *m, char *s);
Download bitproto C library¶
Bitproto serialization requires a language-specific library to work, the generated encoder and decoder depends on the bitproto C library underlying.
Download the bitproto library for C language from
this github link,
and put them (the bitproto.c
and bitproto.h
) to current working directory.
Run the code¶
Now, we create a file named main.c
and put the following code in it:
#include "pen_bp.h"
#include <stdio.h> // for `printf`
int main() {
struct Pen p = {COLOR_RED, 1611515729966};
unsigned char s[BYTES_LENGTH_PEN] = {0};
// Encode p to buffer s.
EncodePen(&p, s);
// Decode buffer s to p1.
struct Pen p1 = {};
DecodePen(&p1, s);
// Format p1 to buffer buf.
char buf[64] = {0};
JsonPen(&p1, buf);
printf("%s", buf);
return 0;
}
In the code above, we firstly create a p
of type struct Pen
with data initilization,
then call a function EncodePen
to encode p
into buffer s
. The length of buffer s
is generated by compiler as a macro defined as BYTES_LENGTH_PEN
.
In the decoding part, we construct another p1
instance of type struct Pen
with zero
initilization, then call a function DecodePen
to decode bytes from buffer s
into p1
.
Finally, use a function JsonPen
generated by the compiler to format the structure p1
to json string to checkout if the decoding works ok.
Let’s compile it with the C library bitproto.c
and generated pen_bp.c
, and run:
$ cc main.c bitproto.c pen_bp.c -o main
$ ./main
{"color":1,"produced_at":1611515729966}
The encoder and decoder copy bits between the structure’s memory and buffer s
byte-to-byte,
the whole call allocates memory on the stack without any dynamic allocations.
There’s another larger example source code on the github.
Naming Prefix¶
As we know, there’s no namespace mechanism to scope definition names across including header files in C.
Bitproto provides an option to add a name prefix to all generated types. To use it, define an option
at the global scope of the bitproto file:
option c.name_prefix = "my_prefix_"
Run the bitproto compiler again, we will that names in pen_bp.h
are changed:
The
enum Color
is now mapped toMyPrefixColor
.The
Timestamp
is now mapped toMyPrefixTimestamp
.The
message Pen
is now mapped tostruct MyPrefixPen
.