Home | History | Annotate | Download | only in source
      1 Use in C    {#flatbuffers_guide_use_c}
      2 ==========
      3 
      4 The C language binding exists in a separate project named [FlatCC](https://github.com/dvidelabs/flatcc).
      5 
      6 The `flatcc` C schema compiler can generate code offline as well as
      7 online via a C library. It can also generate buffer verifiers and fast
      8 JSON parsers, printers.
      9 
     10 Great care has been taken to ensure compatibily with the main `flatc`
     11 project.
     12 
     13 ## General Documention
     14 
     15 - [Tutorial](@ref flatbuffers_guide_tutorial) - select C as language
     16   when scrolling down
     17 - [FlatCC Guide](https://github.com/dvidelabs/flatcc#flatcc-flatbuffers-in-c-for-c)
     18 - [The C Builder Interface](https://github.com/dvidelabs/flatcc/blob/master/doc/builder.md#the-builder-interface)
     19 - [The Monster Sample in C](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c)
     20 - [GitHub](https://github.com/dvidelabs/flatcc)
     21 
     22 
     23 ## Supported Platforms
     24 
     25 - Ubuntu (clang / gcc, ninja / gnu make)
     26 - OS-X (clang / gcc, ninja / gnu make)
     27 - Windows MSVC 2010, 2013, 2015
     28 
     29 CI builds recent versions of gcc, clang and MSVC on OS-X, Ubuntu, and
     30 Windows, and occasionally older compiler versions. See main project [Status](https://github.com/dvidelabs/flatcc#status).
     31 
     32 Other platforms may well work, including Centos, but are not tested
     33 regularly.
     34 
     35 The monster sample project was specifically written for C99 in order to
     36 follow the C++ version and for that reason it will not work with MSVC
     37 2010.
     38 
     39 ## Modular Object Creation
     40 
     41 In the tutorial we used the call `Monster_create_as_root` to create the
     42 root buffer object since this is easier in simple use cases. Sometimes
     43 we need more modularity so we can reuse a function to create nested
     44 tables and root tables the same way. For this we need the
     45 `flatcc_builder_buffer_create_call`. It is best to keep `flatcc_builder`
     46 calls isolated at the top driver level, so we get:
     47 
     48 <div class="language-c">
     49 ~~~{.c}
     50   ns(Monster_ref_t) create_orc(flatcc_builder_t *B)
     51   {
     52     // ... same as in the tutorial.
     53     return s(Monster_create(B, ...));
     54   }
     55 
     56   void create_monster_buffer()
     57   {
     58       uint8_t *buf;
     59       size_t size;
     60       flatcc_builder_t builder, *B;
     61 
     62       // Initialize the builder object.
     63       B = &builder;
     64       flatcc_builder_init(B);
     65       // Only use `buffer_create` without `create/start/end_as_root`.
     66       flatcc_builder_buffer_create(create_orc(B));
     67       // Allocate and copy buffer to user memory.
     68       buf = flatcc_builder_finalize_buffer(B, &size);
     69       // ... write the buffer to disk or network, or something.
     70 
     71       free(buf);
     72       flatcc_builder_clear(B);
     73   }
     74 ~~~
     75 </div>
     76 
     77 The same principle applies with `start/end` vs `start/end_as_root` in
     78 the top-down approach.
     79 
     80 
     81 ## Top Down Example
     82 
     83 The tutorial uses a bottom up approach. In C it is also possible to use
     84 a top-down approach by starting and ending objects nested within each
     85 other. In the tutorial there is no deep nesting, so the difference is
     86 limited, but it shows the idea:
     87 
     88 <div class="language-c">
     89 <br>
     90 ~~~{.c}
     91   uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
     92   size_t treasure_count = c_vec_len(treasure);
     93   ns(Weapon_ref_t) axe;
     94 
     95   // NOTE: if we use end_as_root, we MUST also start as root.
     96   ns(Monster_start_as_root(B));
     97   ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));
     98   ns(Monster_hp_add(B, 300));
     99   ns(Monster_mana_add(B, 150));
    100   // We use create_str instead of add because we have no existing string reference.
    101   ns(Monster_name_create_str(B, "Orc"));
    102   // Again we use create because we no existing vector object, only a C-array.
    103   ns(Monster_inventory_create(B, treasure, treasure_count));
    104   ns(Monster_color_add(B, ns(Color_Red)));
    105   if (1) {
    106       ns(Monster_weapons_start(B));
    107       ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Sword"), 3));
    108       // We reuse the axe object later. Note that we dereference a pointer
    109       // because push always returns a short-term pointer to the stored element.
    110       // We could also have created the axe object first and simply pushed it.
    111       axe = *ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Axe"), 5));
    112       ns(Monster_weapons_end(B));
    113   } else {
    114       // We can have more control with the table elements added to a vector:
    115       //
    116       ns(Monster_weapons_start(B));
    117       ns(Monster_weapons_push_start(B));
    118       ns(Weapon_name_create_str(B, "Sword"));
    119       ns(Weapon_damage_add(B, 3));
    120       ns(Monster_weapons_push_end(B));
    121       ns(Monster_weapons_push_start(B));
    122       ns(Monster_weapons_push_start(B));
    123       ns(Weapon_name_create_str(B, "Axe"));
    124       ns(Weapon_damage_add(B, 5));
    125       axe = *ns(Monster_weapons_push_end(B));
    126       ns(Monster_weapons_end(B));
    127   }
    128   // Unions can get their type by using a type-specific add/create/start method.
    129   ns(Monster_equipped_Weapon_add(B, axe));
    130 
    131   ns(Monster_end_as_root(B));
    132 ~~~
    133 </div>
    134 
    135 
    136 ## Basic Reflection
    137 
    138 The C-API does support reading binary schema (.bfbs)
    139 files via code generated from the `reflection.fbs` schema, and an
    140 [example usage](https://github.com/dvidelabs/flatcc/tree/master/samples/reflection)
    141 shows how to use this. The reflection schema files are pre-generated
    142 in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection).
    143 
    144 
    145 ## Mutations and Reflection
    146 
    147 The C-API does not support mutating reflection like C++ does, nor does
    148 the reader interface support mutating scalars (and it is generally
    149 unsafe to do so even after verification).
    150 
    151 The generated reader interface supports sorting vectors in-place after
    152 casting them to a mutating type because it is not practical to do so
    153 while building a buffer. This is covered in the builder documentation.  
    154 The reflection example makes use of this feature to look up objects by
    155 name.
    156 
    157 It is possible to build new buffers using complex objects from existing
    158 buffers as source. This can be very efficient due to direct copy
    159 semantics without endian conversion or temporary stack allocation.
    160 
    161 Scalars, structs and strings can be used as source, as well vectors of
    162 these.
    163 
    164 It is currently not possible to use an existing table or vector of table
    165 as source, but it would be possible to add support for this at some
    166 point.
    167 
    168 
    169 ## Namespaces
    170 
    171 The `FLATBUFFERS_WRAP_NAMESPACE` approach used in the tutorial is convenient
    172 when each function has a very long namespace prefix. But it isn't always
    173 the best approach. If the namespace is absent, or simple and
    174 informative, we might as well use the prefix directly. The
    175 [reflection example](https://github.com/dvidelabs/flatcc/blob/master/samples/reflection/bfbs2json.c)
    176 mentioned above uses this approach.
    177 
    178 
    179 ## Checking for Present Members
    180 
    181 Not all languages support testing if a field is present, but in C we can
    182 elaborate the reader section of the tutorial with tests for this. Recall
    183 that `mana` was set to the default value `150` and therefore shouldn't
    184 be present.
    185 
    186 <div class="language-c">
    187 ~~~{.c}
    188   int hp_present = ns(Monster_hp_is_present(monster)); // 1
    189   int mana_present = ns(Monster_mana_is_present(monster)); // 0
    190 ~~~
    191 </div>
    192 
    193 ## Alternative ways to add a Union
    194 
    195 In the tutorial we used a single call to add a union.  Here we show
    196 different ways to accomplish the same thing. The last form is rarely
    197 used, but is the low-level way to do it. It can be used to group small
    198 values together in the table by adding type and data at different
    199 points in time.
    200 
    201 <div class="language-c">
    202 ~~~{.c}
    203    ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
    204    ns(Monster_equipped_add(B, equipped));
    205    // or alternatively
    206    ns(Monster_equipped_Weapon_add(B, axe);
    207    // or alternatively
    208    ns(Monster_equipped_add_type(B, ns(Equipment_Weapon));
    209    ns(Monster_equipped_add_member(B, axe));
    210 ~~~
    211 </div>
    212 
    213 ## Why not integrate with the `flatc` tool?
    214 
    215 [It was considered how the C code generator could be integrated into the
    216 `flatc` tool](https://github.com/dvidelabs/flatcc/issues/1), but it
    217 would either require that the standalone C implementation of the schema
    218 compiler was dropped, or it would lead to excessive code duplication, or
    219 a complicated intermediate representation would have to be invented.
    220 Neither of these alternatives are very attractive, and it isn't a big
    221 deal to use the `flatcc` tool instead of `flatc` given that the
    222 FlatBuffers C runtime library needs to be made available regardless.
    223 
    224 
    225