Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API reference: pb.h

The pb.h file contains type and macro definitions shared between nanopb components. It also validates feature enables for preprocessor #if directives and includes the needed system headers.

Data types

pb_allocator_t

An extensible structure for providing a custom allocator to nanob decoder functions. The allocator is used when generator options set a field type to FT_POINTER.

typedef struct pb_allocator_s pb_allocator_t;
struct pb_allocator_s {
    void* (*realloc)(pb_allocator_t *actx, void *ptr, size_t size);
    void (*free)(pb_allocator_t *actx, void *ptr);
    void *state;
};

The two functions follow the behavior of standard C realloc() and free() functions.

The actx arguments is a pointer to the pb_allocator_t structure, which the allocator implementation can use to store its state. The free pointer field state is for user code, it is not used by nanopb. Alternatively the user code can extend the structure definition.

See [tests/custom_allocator](tests/custom_allocator] for an example implementation of an arena allocator.

Custom realloc() implementation

If the ptr argument is NULL, realloc() will make a new memory allocation of size bytes.

If the ptr argument is not NULL, the size of the existing allocation is adjusted to new size. Up to size bytes of data from the old allocation are retained. The realloc() implementation is allowed to make a new allocation, copy the data to the new location and release the old allocation.

Nanopb does not call realloc() with size = 0.

The function returns either NULL on failed allocation, or a valid pointer to an allocation of at least size bytes long.

Custom free() implementation

Releases a previously made allocation. The ptr argument is the return value from a previous call to realloc().

Nanopb does not call free() with ptr = NULL.

pb_byte_t

Type used for storing byte-sized data, such as raw binary input and bytes-type fields.

typedef uint_least8_t pb_byte_t;

For most platforms this is equivalent to uint8_t. Some platforms however do not support 8-bit variables, and on those platforms 16 or 32 bits need to be used for each byte.

pb_tag_t

Type used for storing field tag numbers. By default this is uint32_t:

typedef uint32_t pb_tag_t;

If PB_NO_LARGEMSG build option is given, then uint_least16_t is used instead. This saves some stack space and is sufficient due to the 4095 tag number limit for small messages.

pb_size_t

Type used for storing stream, field and array sizes.tag numbers and sizes of message fields. By default this is equivalent to size_t:

typedef size_t pb_size_t;

If PB_NO_LARGEMSG build option is given, then uint_least16_t is used instead. This saves some stack space and is sufficient due to the 4 kB limit for small messages.

Optionally PB_SIZE_T_OVERRIDE can be used to customize the type. For example, uint8_t could be used for processing tiny messages on a 8-bit platform.

pb_fieldidx_t

Type used for storing index of a field in the protobuf message descriptors. Equivalent to uint_least16_t:

typedef uint_least16_t pb_fieldidx_t;

The value is multiplied by 5 when accessing large format descriptors. This makes a 16-bit type sufficient for up to 13000 fields. According to Google’s Proto Limits, typical protobuf implementations are limited to about 4000 fields per message, so this should be sufficient.

pb_type_t

Type used to store the type of each field, to control the encoder/decoder behaviour.

typedef uint_least16_t pb_type_t;

The macros PB_LTYPE(), PB_HTYPE() and PB_ATYPE() can be used to access individual components of the field type.

The low-order nibble of the enumeration values defines the function that can be used for encoding and decoding the field data:

LTYPE identifierValueStorage format
PB_LTYPE_BOOL0x00Boolean.
PB_LTYPE_VARINT0x01Integer.
PB_LTYPE_UVARINT0x02Unsigned integer.
PB_LTYPE_SVARINT0x03Integer, zigzag encoded.
PB_LTYPE_FIXED320x0432-bit integer or floating point.
PB_LTYPE_FIXED640x0564-bit integer or floating point.
PB_LTYPE_LAST_PACKABLE0x05LTYPEs up to this can be stored in a packed array
PB_LTYPE_BYTES0x06Structure with pb_size_t field and byte array.
PB_LTYPE_STRING0x07Null-terminated string.
PB_LTYPE_SUBMESSAGE0x08Submessage structure.
PB_LTYPE_SUBMSG_W_CB0x09Submessage with pre-decoding callback.
PB_LTYPE_EXTENSION0x0APointer to pb_extension_t.
PB_LTYPE_FIXED_LENGTH_BYTES0x0BInline pb_byte_t array of fixed size.

The bits 4-5 define whether the field is required, optional or repeated. There are separate definitions for semantically different modes, even though some of them share values and are distinguished based on values of other fields:

HTYPE identifierValueField handling
PB_HTYPE_REQUIRED0x00Verify that field exists in decoded message.
PB_HTYPE_OPTIONAL0x10Use separate has_<field> boolean to specify whether the field is present.
PB_HTYPE_SINGULAR0x10Proto3 field, which is present when its value is non-zero.
PB_HTYPE_REPEATED0x20A repeated field with preallocated array. Separate <field>_count for number of items.
PB_HTYPE_FIXARRAY0x20A repeated field that has constant length.
PB_HTYPE_ONEOF0x30Oneof-field, only one of each group can be present.

The bits 6-7 define the how the storage for the field is allocated:

ATYPE identifierValueAllocation method
PB_ATYPE_STATIC0x00Statically allocated storage in the structure.
PB_ATYPE_POINTER0x80Dynamically allocated storage. Struct field contains a pointer to the storage.
PB_ATYPE_CALLBACK0x40A field with dynamic storage size. Struct field contains a pointer to a callback function.

Upper bits 8-10 are available in the large-format message descriptors, but they are reserved for future use.

pb_msgdesc_t

Autogenerated structure that contains information about a message and pointers to the field descriptors. Use functions defined in pb_common.h to process the field information.

typedef struct pb_msgdesc_s pb_msgdesc_t;
struct pb_msgdesc_s {
    pb_size_t struct_size;
    pb_fieldidx_t field_count;
    pb_fieldidx_t required_field_count;
    pb_tag_t largest_tag;
    pb_msgflag_t msg_flags;
    const uint32_t *field_info;
    const pb_msgdesc_t * const * submsg_info;
    const pb_byte_t *default_value;

    bool (*field_callback)(pb_decode_ctx_t *istream, pb_encode_ctx_t *ostream, const pb_field_iter_t *field);
};
struct_sizeMemory size of the associated structure, in bytes.
field_countTotal number of fields in the message.
required_field_countNumber of fields that have the proto2 required specifier.
largest_tagLargest tag number used in the fields of the message.
msg_flagsInforms whether the message contains e.g. pointer fields.
field_infoPointer to compact representation of the field information.
submsg_infoPointer to array of pointers to descriptors for submessages.
default_valueDefault values for this message as an encoded protobuf message.
field_callbackFunction used to handle all callback fields in this message. By default pb_default_field_callback() which loads per-field callbacks from a pb_callback_t structure.

pb_msgflag_t

Message flags are stored in the pb_msgdesc_t and provide high-level metadata about the message. They are primarily used for nanopb code to skip unnecessary steps if the message does not contain particular features.

User code can use the flags to e.g. check if the message contains any pointers that need to be released.

Currently defined message flags are listed below. Flags with PB_MSGFLAG_R_ are recursive, they get set on the parent message if they apply to any submessages.

PB_MSGFLAG_LARGEDESCDescriptor uses the 5 words per field descriptor format.
PB_MSGFLAG_EXTENSIBLEMessage contains proto2 extension fields.
PB_MSGFLAG_R_HAS_PTRSMessage or its submessages contain pointer fields.
PB_MSGFLAG_R_HAS_DEFVALMessage or its submessages have default values.
PB_MSGFLAG_R_HAS_CBSMessage or its submessages have callback fields.
PB_MSGFLAG_R_HAS_EXTSMessage or its submessages have extension fields.

pb_field_iter_t

Describes a single structure field with memory position in relation to others. The field information is stored in a compact format and loaded into pb_field_iter_t by the functions defined in pb_common.h, such as pb_field_iter_next().

typedef struct pb_field_iter_s pb_field_iter_t;
struct pb_field_iter_s {
    const pb_msgdesc_t *descriptor;
    void *message;

    pb_fieldidx_t index;
    pb_fieldidx_t required_field_index;
    pb_fieldidx_t submessage_index;
    pb_fieldidx_t field_info_index;

    pb_tag_t tag;
    pb_size_t data_size;
    pb_size_t array_size;
    pb_type_t type;

    void *pField;
    void *pData;
    void *pSize;

    const pb_msgdesc_t *submsg_desc;
};
descriptorPointer to pb_msgdesc_t for the message that contains this field.
messagePointer to the start of the message structure.
indexIndex of the field inside the message
required_field_indexIndex that counts only the required fields
submessage_indexIndex that counts only submessages
field_info_indexIndex to the internal field_info array
tagTag number defined in .proto file for this field.
data_sizesizeof() of the field in the structure. For repeated fields this is for a single array entry.
array_sizeMaximum number of items in a statically allocated array.
typeProtobuf data type of the field.
pFieldPointer to the field storage in the structure.
pDataPointer to data contents. For arrays and pointers this can be different than pField.
pSizePointer to count or has field, or NULL if this field doesn’t have such.
submsg_descFor submessage fields, points to the descriptor for the submessage.

pb_bytes_array_t

An byte array with a field for storing the length:

typedef struct {
    pb_size_t size;
    pb_byte_t bytes[1];
} pb_bytes_array_t;

In an actual array, the length of bytes is set by generator options. The macros PB_BYTES_ARRAY_T() and PB_BYTES_ARRAY_T_ALLOCSIZE() are used to allocate variable length storage for bytes fields.

pb_callback_t

Part of a message structure, for fields with type PB_HTYPE_CALLBACK:

typedef struct pb_callback_s pb_callback_t;
struct pb_callback_s {
    union {
        bool (*decode)(pb_decode_ctx_t *stream, const pb_field_iter_t *field, void **arg);
        bool (*encode)(pb_encode_ctx_t *stream, const pb_field_iter_t *field, void * const *arg);
    } funcs;

    void *arg;
};

A pointer to the arg is passed to the callback when calling. It can be used to store any information that the callback might need. Note that this is a double pointer. If you set field.arg to point to &data in your main code, in the callback you can access it like this:

myfunction(*arg);           /* Gives pointer to data as argument */
myfunction(*(data_t*)*arg); /* Gives value of data as argument */
*arg = newdata;             /* Alters value of field.arg in structure */

When calling pb_encode(), funcs.encode is used, and similarly when calling pb_decode(), funcs.decode is used. The function pointers are stored in the same memory location but are of incompatible types. You can set the function pointer to NULL to skip the field.

pb_wire_type_t

Protocol Buffers wire types. These are used with pb_encode_tag():

typedef enum {
    PB_WT_VARINT = 0,
    PB_WT_64BIT  = 1,
    PB_WT_STRING = 2,
    PB_WT_32BIT  = 5
} pb_wire_type_t;

pb_extension_t

Ties together the extension field type and the storage for the field value. For message structs that have extensions, the generator will add a pb_extension_t* field. It should point to a linked list of extensions.

typedef struct {
    const pb_msgdesc_t *type;
    void *dest;
    pb_extension_t *next;
    bool found;
} pb_extension_t;
typePointer to the automatically generated descriptor for the extension field contents.
destPointer to the variable that stores the field value.
nextPointer to the next extension handler, or NULL for last handler.
foundDecoder sets this to true if the extension was found.

Utility macros

PB_GET_ERROR

Get the current error message from a context, or a placeholder string if there is no error message:

#define PB_GET_ERROR(ctx) (string expression)

The ctx can have type pb_encode_ctx_t* or pb_decode_ctx_t*.

If the error message is not set, "(none)" is returned. If error messages are disabled with PB_NO_ERRMSG, "(errmsg disabled)" is returned.

This should be used for printing errors, for example:

if (!pb_decode(&ctx, ...))
{
    printf("Decode failed: %s\n", PB_GET_ERROR(&ctx));
}

The macro only returns pointers to constant strings (in code memory), so that there is no need to release the returned pointer.

PB_SET_ERROR

Set the error message if it has not been set yet.

#define PB_SET_ERROR(ctx, msg) (set errmsg if it is null)

If multiple errors occur (for example IO error followed by failed decoding), the first error message will persist.

The msg parameter must be a constant string.

PB_RETURN_ERROR

Set the error message if it is not already set, and return false:

#define PB_RETURN_ERROR(ctx, msg) (PB_SET_ERROR() and returns false)

This should be used to handle error conditions inside nanopb functions and user callback functions:

if (error_condition)
{
    PB_RETURN_ERROR(ctx, "something went wrong");
}

The msg parameter must be a constant string.

PB_READ_ERROR

Sentinel value used by pb_decode_ctx_t stream callbacks to indicate error condition.

#define PB_READ_ERROR PB_SIZE_MAX

The largest value representable by pb_size_t is reserved for error indication by pb_init_decode_ctx_for_callback() limiting the stream length to PB_SIZE_MAX - 1.

PB_BIND

This macro generates the pb_msgdesc_t and associated arrays, based on a list of fields in X-macro format. :

#define PB_BIND(msgname, structname, width) ...
msgnameName of the message type. Expects msgname_FIELDLIST macro to exist.
structnameName of the C structure to bind to.
widthS for small messages up to 4kB, L for large messages.

This macro is automatically invoked inside the autogenerated .pb.c files. User code can also call it to bind message types with custom structures or class types.

pb_arraysize()

Get the number of entries in an array-type member of a structure. Example usage:

MyMessage msg;
for (int i = 0; i < pb_arraysize(MyMessage, my_repeated_int); i++)
{
    printf("%d\n", msg.my_repeated_int[i]);
}

PB_CONST_CAST

Nanopb encoding functions only read from the message structure and thus take const pointer to it. But internally a part of the logic is shared, resulting in a need to cast away the const qualifier. This is done with care, so that no writes are done through the pointer.

The macro implementation uses uintptr_t as an intermediate type to avoid warnings on most compilers:

#define PB_CONST_CAST(x) ((void*)(uintptr_t)(x))

PB_UNUSED

This macro is used to supress compiler warnings about unused function arguments. Typically needed when disabled features result in some arguments being ignored.

#define PB_UNUSED(x) (void)(x)

PB_OPT_ASSERT

Optional assertions that are useful for early detection of problems. This is in particular targeted for nanopb developers, though the assertions do not have significant runtime cost either. All security properties are fulfilled even if assertions are disabled using PB_NO_OPT_ASSERT.

#define PB_OPT_ASSERT(cond) assert(cond)

PB_STATIC_ASSERT

Compile-time assertions, using either C11 _Static_assert keyword or the negative-size-array mechanism in C99.

#define PB_STATIC_ASSERT(COND,MSG) _Static_assert(COND,#MSG);

The implementation of static assertions can be controlled using build options PB_NO_STATIC_ASSERT and PB_C99_STATIC_ASSERT.