Documentation for C bindings

parent a649cb7d
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 effort has been made to ensure compatibily with the main `flatc`
project.
## General Documention
- [Tutorial](@ref flatbuffers_guide_tutorial) - select C as language
when scrolling down
- General Use in C (the README) <https://github.com/dvidelabs/flatcc/blob/master/README.md>
- The C Builder Interface, advanced <https://github.com/dvidelabs/flatcc/blob/master/doc/builder.md>
## 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 schema files are pre-generated
in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection). Extended reflection
## Mutating Reflection
The C-API does not support mutating reflection like C++ does.
Although the following isn't reflection, it is possible to create 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.
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.
## 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.
......@@ -4,8 +4,8 @@ FlatBuffers {#flatbuffers_index}
# Overview {#flatbuffers_overview}
[FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform
serialization library for C++, C#, Go, Java, JavaScript, PHP, and Python
(C and Ruby in progress). It was originally created at Google for game
serialization library for C++, C#, C, Go, Java, JavaScript, PHP, and Python
(Ruby and Swift in progress). It was originally created at Google for game
development and other performance-critical applications.
It is available as Open Source on [GitHub](http://github.com/google/flatbuffers)
......@@ -131,6 +131,8 @@ sections provide a more in-depth usage guide.
in your own programs.
- How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your
own programs.
- How to [use the generated C code](@ref flatbuffers_guide_use_c) in your
own programs.
- [Support matrix](@ref flatbuffers_support) for platforms/languages/features.
- Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of
using FlatBuffers.
......
......@@ -20,17 +20,17 @@ NOTE: this table is a start, it needs to be extended.
Feature | C++ | Java | C# | Go | Python | JS | C | PHP | Ruby
------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | ---- | --- | ----
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP | WiP
JSON parsing | Yes | No | No | No | No | No | No | No | No
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP
JSON parsing | Yes | No | No | No | No | No | Yes | No | No
Simple mutation | Yes | WIP | WIP | No | No | No | No | No | No
Reflection | Yes | No | No | No | No | No | No | No | No
Buffer verifier | Yes | No | No | No | No | No | No | No | No
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | ? | ? | ?
Testing: fuzz | Yes | No | No | Yes | Yes | No | ? | ? | ?
Reflection | Yes | No | No | No | No | No | Basic| No | No
Buffer verifier | Yes | No | No | No | No | No | Yes | No | No
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ?
Testing: fuzz | Yes | No | No | Yes | Yes | No | No | ? | ?
Performance: | Superb | Great | Great | Great | Ok | ? |Superb| ? | ?
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | ? | ? | ?
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | ? | ? | ?
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | ? | ? | ?
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | No | ? | ?
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | ? | ?
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | ? | ?
Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ?
Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ?
Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ?
......
......@@ -23,12 +23,13 @@ Please select your desired language for our quest:
\htmlonly
<form>
<input type="radio" name="language" value="cpp" checked="checked">C++</input>
<input type="radio" name="language" value="java">Java</input>
<input type="radio" name="language" value="csharp">C#</input>
<input type="radio" name="language" value="c">C</input>
<input type="radio" name="language" value="go">Go</input>
<input type="radio" name="language" value="python">Python</input>
<input type="radio" name="language" value="java">Java</input>
<input type="radio" name="language" value="javascript">JavaScript</input>
<input type="radio" name="language" value="php">PHP</input>
<input type="radio" name="language" value="python">Python</input>
</form>
\endhtmlonly
......@@ -98,6 +99,10 @@ Samples demonstating the concepts in this example are located in the source code
package, under the `samples` directory. You can browse the samples on GitHub
[here](https://github.com/google/flatbuffers/tree/master/samples).
<div class="language-c">
*Note: The above does not apply to C, instead [look here](https://github.com/dvidelabs/flatcc/tree/master/samples).*
</div>
For your chosen language, please cross-reference with:
<div class="language-cpp">
......@@ -121,6 +126,9 @@ For your chosen language, please cross-reference with:
<div class="language-php">
[SampleBinary.php](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.php)
</div>
<div class="language-c">
[monster.c](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c)
</div>
## Writing the Monsters' FlatBuffer Schema
......@@ -225,6 +233,16 @@ FlatBuffer compiler.
Once `flatc` is built successfully, compile the schema for your language:
<div class="language-c">
*Note: If you're working in C, you need to use the separate project [FlatCC](https://github.com/dvidelabs/flatcc) which contains a schema compiler and runtime library in C for C.*
<br>
See [flatcc build instructions](https://github.com/dvidelabs/flatcc#building).
<br>
Please be aware of the difference between `flatc` and `flatcc` tools.
<br>
</div>
<div class="language-cpp">
~~~{.sh}
cd flatbuffers/sample
......@@ -267,8 +285,17 @@ Once `flatc` is built successfully, compile the schema for your language:
./../flatc --php samples/monster.fbs
~~~
</div>
<div class="language-c">
~~~{.sh}
cd flatcc
mkdir -p build/tmp/samples/monster
bin/flatcc -a -o build/tmp/samples/monster samples/monster/monster.fbs
# or just
flatcc/samples/monster/build.sh
~~~
</div>
For a more complete guide to using the `flatc` compiler, pleaes read the
For a more complete guide to using the `flatc` compiler, please read the
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
section of the Programmer's Guide.
......@@ -359,6 +386,21 @@ The first step is to import/include the library, generated files, etc.
}
~~~
</div>
<div class="language-c">
~~~{.c}
#include "monster_builder.h" // Generated by `flatcc`.
// Convenient namespace macro to manage long namespace prefix.
#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema.
// Convenient common namespace macro.
#define nsc(x) FLATBUFFERS_WRAP_NAMESPACE(flatbuffers, x)
// A helper to simplify creating vectors from C-arrays.
#define c_vec_len(V) (sizeof(V)/sizeof((V)[0]))
// The ns macro makes it possible to write `ns(Monster_create(...))`
// instead of `MyGame_Sample_Monster_create(...)`.
~~~
</div>
Now we are ready to start building some buffers. In order to start, we need
to create an instance of the `FlatBufferBuilder`, which will contain the buffer
......@@ -413,6 +455,14 @@ as it grows:
$builder = new Google\FlatBuffers\FlatbufferBuilder(0);
~~~
</div>
<div class="language-c">
~~~{.c}
flatcc_builder_t builder, *B;
B = &builder;
// Initialize the builder object.
flatcc_builder_init(B);
~~~
</div>
After creating the `builder`, we can start serializing our data. Before we make
our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
......@@ -525,6 +575,18 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
$weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);
~~~
</div>
<div class="language-c">
~~~{.c}
ns(Weapon_ref_t) weapon_one_name = nsc(string_create_str(B, "Sword"));
uint16_t weapon_one_damage = 3;
ns(Weapon_ref_t) weapon_two_name = nsc(string_create_str(B, "Axe"));
uint16_t weapon_two_damage = 5;
ns(Weapon_ref_t) sword = ns(Weapon_create(B, weapon_one_name, weapon_one_damage));
ns(Weapon_ref_t) axe = ns(Weapon_create(B, weapon_two_name, weapon_two_damage));
~~~
</div>
Now let's create our monster, the `orc`. For this `orc`, lets make him
`red` with rage, positioned at `(1.0, 2.0, 3.0)`, and give him
......@@ -627,6 +689,20 @@ traversal. This is generally easy to do on any tree structures.
$inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure);
~~~
</div>
<div class="language-c">
~~~{.c}
// Serialize a name for our monster, called "Orc".
// The _str suffix indicates the source is an ascii-z string.
nsc(string_ref_t) name = nsc(string_create_str(B, "Orc"));
// Create a `vector` representing the inventory of the Orc. Each number
// could correspond to an item that can be claimed after he is slain.
uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
nsc(uint8_vec_ref_t) inventory;
// `c_vec_len` is the convenience macro we defined earlier.
inventory = nsc(uint8_vec_create(B, treasure, c_vec_len(treasure)));
~~~
</div>
We serialized two built-in data types (`string` and `vector`) and captured
their return values. These values are offsets into the serialized data,
......@@ -642,6 +718,13 @@ and `Axe`). These are both FlatBuffer `table`s, whose offsets we now store in
memory. Therefore we can create a FlatBuffer `vector` to contain these
offsets.
<div class="language-c">
*Note: If you're using C, there is also an often shorter top-down
approach that avoids storing temporary references because the runtime
has an internal stack. The top-down version is shown at the end of build
section.*
</div>
<div class="language-cpp">
~~~{.cpp}
// Place the weapons into a `std::vector`, then convert that into a FlatBuffer `vector`.
......@@ -709,8 +792,21 @@ offsets.
$weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);
~~~
</div>
<div class="language-c">
~~~{.c}
// Here we use a top-down approach locally to build a Weapons vector
// in-place instead of creating a temporary external vector to use
// as argument like we did with the `inventory` earlier on, but the
// overall approach is still bottom-up.
ns(Weapon_vec_start(B));
ns(Weapon_vec_push(B, sword));
ns(Weapon_vec_push(B, axe));
ns(Weapon_vec_ref_t) weapons = ns(Weapon_vec_end(B));
~~~
</div>
To create a `struct`, use the `Vec3` class/struct that was generated by `flatc`:
To create a `struct`, use the `Vec3` class/struct that was generated by
the schema compiler:
<div class="language-cpp">
~~~{.cpp}
......@@ -754,6 +850,12 @@ To create a `struct`, use the `Vec3` class/struct that was generated by `flatc`:
$pos = \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
~~~
</div>
<div class="language-c">
~~~{.c}
// Create a `Vec3`, representing the Orc's position in 3-D space.
ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f };
~~~
</div>
We have now serialized the non-scalar components of the orc, so we
can serialize the monster itself:
......@@ -862,10 +964,31 @@ can serialize the monster itself:
$orc = \MyGame\Sample\Monster::EndMonster($builder);
~~~
</div>
<div class="language-c">
~~~{.c}
// Set his hit points to 300 and his mana to 150.
uint16_t hp = 300;
uint16_t mana = 150;
// Create the equipment union. In the C++ language API this is given
// as two arguments to the create call, or as two separate add
// operations for the type and the table reference. In C we create
// a single union value that carries both the type and reference.
ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red),
weapons, equipped));
~~~
</div>
<div class="language-c">
*Note: in C we use `create_as_root` instead of the also valid `create` call
because it simplfies constructing the root object.*
</div>
<div class="language-cpp">
<br>
*Note: Since we passing `150` as the `mana` field, which happens to be the
*Note: Since we are passing `150` as the `mana` field, which happens to be the
default value, the field will not actually be written to the buffer, since the
default value will be returned on query anyway. This is a nice space savings,
especially if default values are common in your data. It also means that you do
......@@ -892,6 +1015,39 @@ a bit more flexibility.
auto orc = monster_builder.Finish();
~~~
</div>
<div class="language-c">
<br>
*Note: Since we are passing `150` as the `mana` field, which happens to be the
default value, the field will not actually be written to the buffer, since the
default value will be returned on query anyway. This is a nice space savings,
especially if default values are common in your data. It also means that you do
not need to be worried of adding a lot of fields that are only used in a small
number of instances, as it will not bloat the buffer if unused.*
<br><br>
If you do not wish to set every field in a `table`, it may be more convenient to
manually set each field of your monster, instead of calling `create_monster_as_root()`.
The following snippet is functionally equivalent to the above code, but provides
a bit more flexibility.
<br>
~~~{.c}
// It is important to pair `start_as_root` with `end_as_root`.
ns(Monster_start_as_root(B));
ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));
// or alternatively
//ns(Monster_pos_add(&pos);
ns(Monster_hp_add(B, hp));
// Notice that `Monser_name_add` adds a string reference unlike the
// add_str and add_strn variants.
ns(Monster_name_add(B, name));
ns(Monster_inventory_add(B, inventory));
ns(Monster_color_add(B, ns(Color_Red)));
ns(Monster_weapons_add(B, weapons));
ns(Monster_equipped_add(B, equipped));
// Complete the monster object and make it the buffer root object.
ns(Monster_end_as_root(B));
~~~
</div>
Before finishing the serialization, let's take a quick look at FlatBuffer
`union Equipped`. There are two parts to each FlatBuffer `union`. The first, is
......@@ -902,6 +1058,11 @@ Second, is the `union`'s data.
In our example, the last two things we added to our `Monster` were the
`Equipped Type` and the `Equipped` union itself.
<div class="language-c">
*Note: In C, several different helpers make these two fields appear as
one field, but they can be added separately.*
</div>
Here is a repetition these lines, to help highlight them more clearly:
<div class="language-cpp">
......@@ -947,11 +1108,78 @@ Here is a repetition these lines, to help highlight them more clearly:
\MyGame\Sample\Monster::AddEquipped($builder, $axe); // Union data
~~~
</div>
<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_type_add(B, ns(Equipment_Weapon));
ns(Monster_equipped_add_member(B, axe));
~~~
</div>
<div class="language-c">
Here is an alternative top-down approach unique to the C builder
library.
<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, nsc(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, nsc(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>
After you have created your buffer, you will have the offset to the root of the
data in the `orc` variable, so you can finish the buffer by calling the
appropriate `finish` method.
<div class="language-c">
*Note: C does not have a `finish` call, and it is not needed when we use
`create_as_root` or `start/end_as_root`. For the sake of modularity, it
is sometimes useful to create an object without knowing if it will be a
root. We show this below, but do NOT mix it with the `_as_root` calls.*
</div>
<div class="language-cpp">
~~~{.cpp}
// Call `Finish()` to instruct the builder that this monster is complete.
......@@ -999,6 +1227,14 @@ appropriate `finish` method.
// $builder, $orc);`.
~~~
</div>
<div class="language-c">
~~~{.c}
// Alternative approach separating object creation from being root object.
ns(Monster_ref_t) orc = ns(Monster_create(B, ...));
// `flatcc_` calls should be isolated to top-level driver logic.
flatcc_builder_buffer_create(orc);
~~~
</div>
The buffer is now ready to be stored somewhere, sent over the network, be
compressed, or whatever you'd like to do with it. You can access the buffer
......@@ -1048,6 +1284,29 @@ like so:
$buf = $builder->dataBuffer(); // Of type `Google\FlatBuffers\ByteBuffer`
~~~
</div>
<div class="language-c">
~~~{.c}
uint8_t *buf;
size_t size;
// Allocate and extract a readable buffer from internal builder heap.
// The returned buffer must be deallocated using `free`.
// NOTE: Finalizing the buffer does NOT change the builder, it
// just creates a snapshot of the builder content.
buf = flatcc_builder_finalize_buffer(&builder, &size);
// use buf
free(buf);
// Optionally reset builder to reuse builder without deallocating
// internal stack and heap.
flatcc_builder_reset(B);
// build next buffer.
// ...
// Cleanup.
flatcc_builder_clear(B);
~~~
</div>
#### Reading Orc FlatBuffers
......@@ -1055,9 +1314,15 @@ Now that we have successfully created an `Orc` FlatBuffer, the monster data can
be saved, sent over a network, etc. Let's now adventure into the inverse, and
deserialize a FlatBuffer.
This seciton requires the same import/include, namespace, etc. requirements as
This section requires the same import/include, namespace, etc. requirements as
before:
<div class="language-c">
*Note: In C there is a separate include file for the reader which is automatically
included by the generated builder header. A standalone reader only depends on header
files while the builder must link with a small runtime library.*
</div>
<div class="language-cpp">
~~~{.cpp}
#include "monster_generate.h" // This was generated by `flatc`.
......@@ -1134,6 +1399,14 @@ before:
}
~~~
</div>
<div class="language-c">
~~~{.c}
#include "monster_reader.h"
#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema.
#define nsc(x) FLATBUFFERS_WRAP_NAMESPACE(flatbuffers, x)
~~~
</div>
Then, assuming you have a variable containing to the bytes of data from disk,
network, etc., you can create a monster from this data:
......@@ -1224,8 +1497,18 @@ network, etc., you can create a monster from this data:
$monster = \MyGame\Sample\Monster::GetRootAsMonster($buf);
~~~
</div>
<div class="language-c">
~~~{.c}
// Note that we use the `table_t` suffix when reading a table object
// as opposed to the `ref_t` suffix used during the construction of
// the buffer.
ns(Monster_table_t) monster = ns(Monster_as_root(buffer));
If you look in the generated files from `flatc`, you will see it generated
// Note: root object pointers are NOT the same as the `buffer` pointer.
~~~
</div>
If you look in the generated files from the schema compiler, you will see it generated
accessors for all non-`deprecated` fields. For example:
<div class="language-cpp">
......@@ -1279,10 +1562,32 @@ accessors for all non-`deprecated` fields. For example:
$name = monster->getName();
~~~
</div>
<div class="language-c">
~~~{.c}
uint16_t hp = ns(Monster_hp(monster));
// Since 150 is the default, we are reading a value that wasn't stored.
uint16_t mana = ns(Monster_mana(monster));
// This is just a const char *, but it also supports a fast length operation.
nsc(string_t) name = ns(Monster_name(monster));
size_t name_len = nsc(string_len(name));
~~~
</div>
<div class="language-c">
*Note: In C we can check if a field is present. For example `mana`
should not be present because it was set with a default value or not at
all, but `hp` should be present.*
~~~{.c}
int hp_present = ns(Monster_hp_is_present(monster)); // 1
int mana_present = ns(Monster_mana_is_present(monster)); // 0
~~~
</div>
These should hold `300`, `150`, and `"Orc"` respectively.
*Note: We never stored a value in `mp`, so we got the default value of `150`.*
*Note: We never stored a value in `mana`, so we got the default value of `150`.*
To access sub-objects, in the case of our `pos`, which is a `Vec3`:
......@@ -1348,10 +1653,25 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`:
$z = $pos->getZ();
~~~
</div>
<div class="language-c">
~~~{.c}
ns(Vec3_struct_t) pos = ns(Monster_pos(monster));
float x = ns(Vec3_x(pos));
float y = ns(Vec3_y(pos));
float z = ns(Vec3_z(pos));
// or alternatively
ns(Vec3_t) pos_vec;
// `pe` indicates endian conversion from protocol to native.
ns(Vec3_copy_from_pe(&pos_vec, pos));
x = pos_vec.x;
// ...
~~~
</div>
`x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0`, respectively.
*Note: Had we not set `pos` during serialization, it would be `NULL`-value.*
*Note: Had we not set `pos` during serialization, it would be a `NULL`-value.*
Similarly, we can access elements of the inventory `vector` by indexing it. You
can also iterate over the length of the array/vector representing the
......@@ -1400,6 +1720,19 @@ FlatBuffers `vector`.
$third_item = $monster->getInventory(2);
~~~
</div>
<div class="language-c">
~~~{.c}
// This is a const uint8_t *, but it shouldn't be accessed directly
// to ensure proper endian conversion. Incidentally the uint8 (ubyte)
// is not sensitive to endianness, so we *could* have accessed it directly.
// The compiler likely optimizes this so that it doesn't matter.
nsc(uint8_vec_t) inv = ns(Monster_inventory(monster));
size_t inv_len = nsc(uint8_vec_len(inv));
// If `inv` was not set, it will be null, but the length is still
// valid to read and will then be zero.
~~~
</div>
For `vector`s of `table`s, you can access the elements like any other vector,
except your need to handle the result as a FlatBuffer `table`:
......@@ -1458,6 +1791,15 @@ except your need to handle the result as a FlatBuffer `table`:
$second_weapon_damage = $monster->getWeapons(1)->getDamage();
~~~
</div>
<div class="language-c">
~~~{.c}
ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster));
size_t weapons_len = ns(Weapon_vec_len(weapons));
// We don't have to use `nsc(string_t)` as type if we don't need fast length access.
const char *second_weapon_name = ns(Weapon_name(ns(Weapon_vec_at(weapons, 1))));
uint16_t second_weapon_damage = ns(Weapon_damage(ns(Weapon_vec_at(weapons, 1))));
~~~
</div>
Last, we can access our `Equipped` FlatBuffer `union`. Just like when we created
the `union`, we need to get both parts of the `union`: the type and the data.
......@@ -1560,9 +1902,26 @@ We can access the type to dynamically cast the data as needed (since the
}
~~~
</div>
<div class="language-c">
~~~{.c}
// Access union type field.
if (ns(Monster_equipped_type(monster)) == ns(Equipment_Weapon)) {
// Cast to appropriate type:
// C allows for silent void pointer assignment, so we need no explicit cast.
ns(Weapon_table_t) weapon = ns(Monster_equipped(monster));
const char *weapon_name = ns(Weapon_name(weapon)); // "Axe"
uint16_t weapon_damage = ns(Weapon_damage(weapon)); // 5
}
~~~
</div>
## Mutating FlatBuffers
<div class="language-c">
*Note: This section does not fully apply to C which has no generated mutation
interface (except for sorting vectors in-place which is an advanced topic).*
</div>
As you saw above, typically once you have created a FlatBuffer, it is read-only
from that moment on. There are, however, cases where you have just received a
FlatBuffer, and you'd like to modify something about it before sending it on to
......@@ -1624,6 +1983,11 @@ mutators like so:
<API for mutating FlatBuffers is not yet supported in PHP.>
~~~
</div>
<div class="language-c">
~~~{.php}
<API for in-place mutating FlatBuffers will not be supported in C.>
~~~
</div>
We use the somewhat verbose term `mutate` instead of `set` to indicate that this
is a special use case, not to be confused with the default way of constructing
......@@ -1687,6 +2051,14 @@ FlatBuffer binary representation of the contents from our `.json` file.
[Use in C++](@ref flatbuffers_guide_use_cpp) section of the Programmer's
Guide for more information.*
</div>
<div class="language-c">
*Note: If you're working in C, the `flatcc --json` (not `flatc`)
compiler will generate schema specific high performance json parsers and
printers that you can compile and use at runtime. The `flatc` compiler (not
`flatcc`) on the other hand, is still useful for general offline json to
flatbuffer conversion from a given schema. There are no current plans
for `flatcc` to support this.*
</div>
## Advanced Features for Each Language
......@@ -1716,5 +2088,8 @@ For your chosen language, see:
<div class="language-php">
[Use in PHP](@ref flatbuffers_guide_use_php)
</div>
<div class="language-c">
[Use in C](@ref flatbuffers_guide_use_c)
</div>
<br>
......@@ -750,6 +750,7 @@ INPUT = "FlatBuffers.md" \
"Compiler.md" \
"Schemas.md" \
"CppUsage.md" \
"CUsage.md" \
"GoUsage.md" \
"JavaCsharpUsage.md" \
"JavaScriptUsage.md" \
......
......@@ -25,6 +25,8 @@
title="Writing a schema"/>
<tab type="user" url="@ref flatbuffers_guide_use_cpp"
title="Use in C++"/>
<tab type="user" url="@ref flatbuffers_guide_use_c"
title="Use in C"/>
<tab type="user" url="@ref flatbuffers_guide_use_go"
title="Use in Go"/>
<tab type="user" url="@ref flatbuffers_guide_use_java_c-sharp"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment