...

Text file src/github.com/google/flatbuffers/docs/source/CUsage.md

Documentation: github.com/google/flatbuffers/docs/source

     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 compatibility 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

View as plain text