1Use in C {#flatbuffers_guide_use_c} 2========== 3 4The C language binding exists in a separate project named [FlatCC](https://github.com/dvidelabs/flatcc). 5 6The `flatcc` C schema compiler can generate code offline as well as 7online via a C library. It can also generate buffer verifiers and fast 8JSON parsers, printers. 9 10Great care has been taken to ensure compatibily with the main `flatc` 11project. 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 29CI builds recent versions of gcc, clang and MSVC on OS-X, Ubuntu, and 30Windows, and occasionally older compiler versions. See main project [Status](https://github.com/dvidelabs/flatcc#status). 31 32Other platforms may well work, including Centos, but are not tested 33regularly. 34 35The monster sample project was specifically written for C99 in order to 36follow the C++ version and for that reason it will not work with MSVC 372010. 38 39## Modular Object Creation 40 41In the tutorial we used the call `Monster_create_as_root` to create the 42root buffer object since this is easier in simple use cases. Sometimes 43we need more modularity so we can reuse a function to create nested 44tables and root tables the same way. For this we need the 45`flatcc_builder_buffer_create_call`. It is best to keep `flatcc_builder` 46calls 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 77The same principle applies with `start/end` vs `start/end_as_root` in 78the top-down approach. 79 80 81## Top Down Example 82 83The tutorial uses a bottom up approach. In C it is also possible to use 84a top-down approach by starting and ending objects nested within each 85other. In the tutorial there is no deep nesting, so the difference is 86limited, 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 138The C-API does support reading binary schema (.bfbs) 139files via code generated from the `reflection.fbs` schema, and an 140[example usage](https://github.com/dvidelabs/flatcc/tree/master/samples/reflection) 141shows how to use this. The reflection schema files are pre-generated 142in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection). 143 144 145## Mutations and Reflection 146 147The C-API does not support mutating reflection like C++ does, nor does 148the reader interface support mutating scalars (and it is generally 149unsafe to do so even after verification). 150 151The generated reader interface supports sorting vectors in-place after 152casting them to a mutating type because it is not practical to do so 153while building a buffer. This is covered in the builder documentation. 154The reflection example makes use of this feature to look up objects by 155name. 156 157It is possible to build new buffers using complex objects from existing 158buffers as source. This can be very efficient due to direct copy 159semantics without endian conversion or temporary stack allocation. 160 161Scalars, structs and strings can be used as source, as well vectors of 162these. 163 164It is currently not possible to use an existing table or vector of table 165as source, but it would be possible to add support for this at some 166point. 167 168 169## Namespaces 170 171The `FLATBUFFERS_WRAP_NAMESPACE` approach used in the tutorial is convenient 172when each function has a very long namespace prefix. But it isn't always 173the best approach. If the namespace is absent, or simple and 174informative, we might as well use the prefix directly. The 175[reflection example](https://github.com/dvidelabs/flatcc/blob/master/samples/reflection/bfbs2json.c) 176mentioned above uses this approach. 177 178 179## Checking for Present Members 180 181Not all languages support testing if a field is present, but in C we can 182elaborate the reader section of the tutorial with tests for this. Recall 183that `mana` was set to the default value `150` and therefore shouldn't 184be 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 195In the tutorial we used a single call to add a union. Here we show 196different ways to accomplish the same thing. The last form is rarely 197used, but is the low-level way to do it. It can be used to group small 198values together in the table by adding type and data at different 199points 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 217would either require that the standalone C implementation of the schema 218compiler was dropped, or it would lead to excessive code duplication, or 219a complicated intermediate representation would have to be invented. 220Neither of these alternatives are very attractive, and it isn't a big 221deal to use the `flatcc` tool instead of `flatc` given that the 222FlatBuffers C runtime library needs to be made available regardless. 223 224 225