| Use in C {#flatbuffers_guide_use_c} | |
| ========== | |
| The C language binding exists in a separate project named [FlatCC](https://github.com/dvidelabs/flatcc). | |
| The `flatcc` C schema compiler can generate code offline as well as | |
| online via a C library. It can also generate buffer verifiers and fast | |
| JSON parsers, printers. | |
| Great care has been taken to ensure compatibily with the main `flatc` | |
| project. | |
| ## General Documention | |
| - [Tutorial](@ref flatbuffers_guide_tutorial) - select C as language | |
| when scrolling down | |
| - [FlatCC Guide](https://github.com/dvidelabs/flatcc#flatcc-flatbuffers-in-c-for-c) | |
| - [The C Builder Interface](https://github.com/dvidelabs/flatcc/blob/master/doc/builder.md#the-builder-interface) | |
| - [The Monster Sample in C](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c) | |
| - [GitHub](https://github.com/dvidelabs/flatcc) | |
| ## Supported Platforms | |
| - Ubuntu (clang / gcc, ninja / gnu make) | |
| - OS-X (clang / gcc, ninja / gnu make) | |
| - Windows MSVC 2010, 2013, 2015 | |
| CI builds recent versions of gcc, clang and MSVC on OS-X, Ubuntu, and | |
| Windows, and occasionally older compiler versions. See main project [Status](https://github.com/dvidelabs/flatcc#status). | |
| Other platforms may well work, including Centos, but are not tested | |
| regularly. | |
| The monster sample project was specifically written for C99 in order to | |
| follow the C++ version and for that reason it will not work with MSVC | |
| 2010. | |
| ## Modular Object Creation | |
| In the tutorial we used the call `Monster_create_as_root` to create the | |
| root buffer object since this is easier in simple use cases. Sometimes | |
| we need more modularity so we can reuse a function to create nested | |
| tables and root tables the same way. For this we need the | |
| `flatcc_builder_buffer_create_call`. It is best to keep `flatcc_builder` | |
| calls isolated at the top driver level, so we get: | |
| <div class="language-c"> | |
| ~~~{.c} | |
| ns(Monster_ref_t) create_orc(flatcc_builder_t *B) | |
| { | |
| // ... same as in the tutorial. | |
| return s(Monster_create(B, ...)); | |
| } | |
| void create_monster_buffer() | |
| { | |
| uint8_t *buf; | |
| size_t size; | |
| flatcc_builder_t builder, *B; | |
| // Initialize the builder object. | |
| B = &builder; | |
| flatcc_builder_init(B); | |
| // Only use `buffer_create` without `create/start/end_as_root`. | |
| flatcc_builder_buffer_create(create_orc(B)); | |
| // Allocate and copy buffer to user memory. | |
| buf = flatcc_builder_finalize_buffer(B, &size); | |
| // ... write the buffer to disk or network, or something. | |
| free(buf); | |
| flatcc_builder_clear(B); | |
| } | |
| ~~~ | |
| </div> | |
| The same principle applies with `start/end` vs `start/end_as_root` in | |
| the top-down approach. | |
| ## Top Down Example | |
| The tutorial uses a bottom up approach. In C it is also possible to use | |
| a top-down approach by starting and ending objects nested within each | |
| other. In the tutorial there is no deep nesting, so the difference is | |
| limited, but it shows the idea: | |
| <div class="language-c"> | |
| <br> | |
| ~~~{.c} | |
| uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | |
| size_t treasure_count = c_vec_len(treasure); | |
| ns(Weapon_ref_t) axe; | |
| // NOTE: if we use end_as_root, we MUST also start as root. | |
| ns(Monster_start_as_root(B)); | |
| ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f)); | |
| ns(Monster_hp_add(B, 300)); | |
| ns(Monster_mana_add(B, 150)); | |
| // We use create_str instead of add because we have no existing string reference. | |
| ns(Monster_name_create_str(B, "Orc")); | |
| // Again we use create because we no existing vector object, only a C-array. | |
| ns(Monster_inventory_create(B, treasure, treasure_count)); | |
| ns(Monster_color_add(B, ns(Color_Red))); | |
| if (1) { | |
| ns(Monster_weapons_start(B)); | |
| ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Sword"), 3)); | |
| // We reuse the axe object later. Note that we dereference a pointer | |
| // because push always returns a short-term pointer to the stored element. | |
| // We could also have created the axe object first and simply pushed it. | |
| axe = *ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Axe"), 5)); | |
| ns(Monster_weapons_end(B)); | |
| } else { | |
| // We can have more control with the table elements added to a vector: | |
| // | |
| ns(Monster_weapons_start(B)); | |
| ns(Monster_weapons_push_start(B)); | |
| ns(Weapon_name_create_str(B, "Sword")); | |
| ns(Weapon_damage_add(B, 3)); | |
| ns(Monster_weapons_push_end(B)); | |
| ns(Monster_weapons_push_start(B)); | |
| ns(Monster_weapons_push_start(B)); | |
| ns(Weapon_name_create_str(B, "Axe")); | |
| ns(Weapon_damage_add(B, 5)); | |
| axe = *ns(Monster_weapons_push_end(B)); | |
| ns(Monster_weapons_end(B)); | |
| } | |
| // Unions can get their type by using a type-specific add/create/start method. | |
| ns(Monster_equipped_Weapon_add(B, axe)); | |
| ns(Monster_end_as_root(B)); | |
| ~~~ | |
| </div> | |
| ## Basic Reflection | |
| The C-API does support reading binary schema (.bfbs) | |
| files via code generated from the `reflection.fbs` schema, and an | |
| [example usage](https://github.com/dvidelabs/flatcc/tree/master/samples/reflection) | |
| shows how to use this. The reflection schema files are pre-generated | |
| in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection). | |
| ## Mutations and Reflection | |
| The C-API does not support mutating reflection like C++ does, nor does | |
| the reader interface support mutating scalars (and it is generally | |
| unsafe to do so even after verification). | |
| The generated reader interface supports sorting vectors in-place after | |
| casting them to a mutating type because it is not practical to do so | |
| while building a buffer. This is covered in the builder documentation. | |
| The reflection example makes use of this feature to look up objects by | |
| name. | |
| It is possible to build new buffers using complex objects from existing | |
| buffers as source. This can be very efficient due to direct copy | |
| semantics without endian conversion or temporary stack allocation. | |
| Scalars, structs and strings can be used as source, as well vectors of | |
| these. | |
| It is currently not possible to use an existing table or vector of table | |
| as source, but it would be possible to add support for this at some | |
| point. | |
| ## Namespaces | |
| The `FLATBUFFERS_WRAP_NAMESPACE` approach used in the tutorial is convenient | |
| when each function has a very long namespace prefix. But it isn't always | |
| the best approach. If the namespace is absent, or simple and | |
| informative, we might as well use the prefix directly. The | |
| [reflection example](https://github.com/dvidelabs/flatcc/blob/master/samples/reflection/bfbs2json.c) | |
| mentioned above uses this approach. | |
| ## Checking for Present Members | |
| Not all languages support testing if a field is present, but in C we can | |
| elaborate the reader section of the tutorial with tests for this. Recall | |
| that `mana` was set to the default value `150` and therefore shouldn't | |
| be present. | |
| <div class="language-c"> | |
| ~~~{.c} | |
| int hp_present = ns(Monster_hp_is_present(monster)); // 1 | |
| int mana_present = ns(Monster_mana_is_present(monster)); // 0 | |
| ~~~ | |
| </div> | |
| ## Alternative ways to add a Union | |
| In the tutorial we used a single call to add a union. Here we show | |
| different ways to accomplish the same thing. The last form is rarely | |
| used, but is the low-level way to do it. It can be used to group small | |
| values together in the table by adding type and data at different | |
| points in time. | |
| <div class="language-c"> | |
| ~~~{.c} | |
| ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe)); | |
| ns(Monster_equipped_add(B, equipped)); | |
| // or alternatively | |
| ns(Monster_equipped_Weapon_add(B, axe); | |
| // or alternatively | |
| ns(Monster_equipped_add_type(B, ns(Equipment_Weapon)); | |
| ns(Monster_equipped_add_member(B, axe)); | |
| ~~~ | |
| </div> | |
| ## Why not integrate with the `flatc` tool? | |
| [It was considered how the C code generator could be integrated into the | |
| `flatc` tool](https://github.com/dvidelabs/flatcc/issues/1), but it | |
| would either require that the standalone C implementation of the schema | |
| compiler was dropped, or it would lead to excessive code duplication, or | |
| a complicated intermediate representation would have to be invented. | |
| Neither of these alternatives are very attractive, and it isn't a big | |
| deal to use the `flatcc` tool instead of `flatc` given that the | |
| FlatBuffers C runtime library needs to be made available regardless. | |