blob: dd5a5115c727645901090c3fb029064f780ecf96 [file] [log] [blame]
<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.9.1"/>
<title>FlatBuffers: Use in C</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
<link href="style.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="commonprojectlogo">
<img alt="Logo" src="fpl_logo_small.png"/>
</td>
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.9.1 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
/* @license-end */</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(document).ready(function(){initNavTree('flatbuffers_guide_use_c.html',''); initResizable(); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div class="PageDoc"><div class="header">
<div class="headertitle">
<div class="title">Use in C </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><a class="anchor" id="md_CUsage"></a></p>
<p>The C language binding exists in a separate project named <a href="https://github.com/dvidelabs/flatcc">FlatCC</a>.</p>
<p>The <code>flatcc</code> 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.</p>
<p>Great care has been taken to ensure compatibily with the main <code>flatc</code> project.</p>
<h1><a class="anchor" id="autotoc_md60"></a>
General Documention</h1>
<ul>
<li><a class="el" href="flatbuffers_guide_tutorial.html">Tutorial</a> - select C as language when scrolling down</li>
<li><a href="https://github.com/dvidelabs/flatcc#flatcc-flatbuffers-in-c-for-c">FlatCC Guide</a></li>
<li><a href="https://github.com/dvidelabs/flatcc/blob/master/doc/builder.md#the-builder-interface">The C Builder Interface</a></li>
<li><a href="https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c">The Monster Sample in C</a></li>
<li><a href="https://github.com/dvidelabs/flatcc">GitHub</a></li>
</ul>
<h1><a class="anchor" id="autotoc_md61"></a>
Supported Platforms</h1>
<ul>
<li>Ubuntu (clang / gcc, ninja / gnu make)</li>
<li>OS-X (clang / gcc, ninja / gnu make)</li>
<li>Windows MSVC 2010, 2013, 2015</li>
</ul>
<p>CI builds recent versions of gcc, clang and MSVC on OS-X, Ubuntu, and Windows, and occasionally older compiler versions. See main project <a href="https://github.com/dvidelabs/flatcc#status">Status</a>.</p>
<p>Other platforms may well work, including Centos, but are not tested regularly.</p>
<p>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.</p>
<h1><a class="anchor" id="autotoc_md62"></a>
Modular Object Creation</h1>
<p>In the tutorial we used the call <code>Monster_create_as_root</code> 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 <code>flatcc_builder_buffer_create_call</code>. It is best to keep <code>flatcc_builder</code> calls isolated at the top driver level, so we get:</p>
<div class="language-c"> <div class="fragment"><div class="line">ns(Monster_ref_t) create_orc(flatcc_builder_t *B)</div>
<div class="line">{</div>
<div class="line"> <span class="comment">// ... same as in the tutorial.</span></div>
<div class="line"> <span class="keywordflow">return</span> s(Monster_create(B, ...));</div>
<div class="line">}</div>
<div class="line"> </div>
<div class="line"><span class="keywordtype">void</span> create_monster_buffer()</div>
<div class="line">{</div>
<div class="line"> uint8_t *buf;</div>
<div class="line"> <span class="keywordtype">size_t</span> size;</div>
<div class="line"> flatcc_builder_t builder, *B;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Initialize the builder object.</span></div>
<div class="line"> B = &amp;builder;</div>
<div class="line"> flatcc_builder_init(B);</div>
<div class="line"> <span class="comment">// Only use `buffer_create` without `create/start/end_as_root`.</span></div>
<div class="line"> flatcc_builder_buffer_create(create_orc(B));</div>
<div class="line"> <span class="comment">// Allocate and copy buffer to user memory.</span></div>
<div class="line"> buf = flatcc_builder_finalize_buffer(B, &amp;size);</div>
<div class="line"> <span class="comment">// ... write the buffer to disk or network, or something.</span></div>
<div class="line"> </div>
<div class="line"> free(buf);</div>
<div class="line"> flatcc_builder_clear(B);</div>
<div class="line">}</div>
</div><!-- fragment --> </div><p>The same principle applies with <code>start/end</code> vs <code>start/end_as_root</code> in the top-down approach.</p>
<h1><a class="anchor" id="autotoc_md63"></a>
Top Down Example</h1>
<p>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:</p>
<div class="language-c"> <br />
<div class="fragment"><div class="line">uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};</div>
<div class="line"><span class="keywordtype">size_t</span> treasure_count = c_vec_len(treasure);</div>
<div class="line">ns(Weapon_ref_t) axe;</div>
<div class="line"> </div>
<div class="line"><span class="comment">// NOTE: if we use end_as_root, we MUST also start as root.</span></div>
<div class="line">ns(Monster_start_as_root(B));</div>
<div class="line">ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));</div>
<div class="line">ns(Monster_hp_add(B, 300));</div>
<div class="line">ns(Monster_mana_add(B, 150));</div>
<div class="line"><span class="comment">// We use create_str instead of add because we have no existing string reference.</span></div>
<div class="line">ns(Monster_name_create_str(B, <span class="stringliteral">&quot;Orc&quot;</span>));</div>
<div class="line"><span class="comment">// Again we use create because we no existing vector object, only a C-array.</span></div>
<div class="line">ns(Monster_inventory_create(B, treasure, treasure_count));</div>
<div class="line">ns(Monster_color_add(B, ns(Color_Red)));</div>
<div class="line"><span class="keywordflow">if</span> (1) {</div>
<div class="line"> ns(Monster_weapons_start(B));</div>
<div class="line"> ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, <span class="stringliteral">&quot;Sword&quot;</span>), 3));</div>
<div class="line"> <span class="comment">// We reuse the axe object later. Note that we dereference a pointer</span></div>
<div class="line"> <span class="comment">// because push always returns a short-term pointer to the stored element.</span></div>
<div class="line"> <span class="comment">// We could also have created the axe object first and simply pushed it.</span></div>
<div class="line"> axe = *ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, <span class="stringliteral">&quot;Axe&quot;</span>), 5));</div>
<div class="line"> ns(Monster_weapons_end(B));</div>
<div class="line">} <span class="keywordflow">else</span> {</div>
<div class="line"> <span class="comment">// We can have more control with the table elements added to a vector:</span></div>
<div class="line"> <span class="comment">//</span></div>
<div class="line"> ns(Monster_weapons_start(B));</div>
<div class="line"> ns(Monster_weapons_push_start(B));</div>
<div class="line"> ns(Weapon_name_create_str(B, <span class="stringliteral">&quot;Sword&quot;</span>));</div>
<div class="line"> ns(Weapon_damage_add(B, 3));</div>
<div class="line"> ns(Monster_weapons_push_end(B));</div>
<div class="line"> ns(Monster_weapons_push_start(B));</div>
<div class="line"> ns(Monster_weapons_push_start(B));</div>
<div class="line"> ns(Weapon_name_create_str(B, <span class="stringliteral">&quot;Axe&quot;</span>));</div>
<div class="line"> ns(Weapon_damage_add(B, 5));</div>
<div class="line"> axe = *ns(Monster_weapons_push_end(B));</div>
<div class="line"> ns(Monster_weapons_end(B));</div>
<div class="line">}</div>
<div class="line"><span class="comment">// Unions can get their type by using a type-specific add/create/start method.</span></div>
<div class="line">ns(Monster_equipped_Weapon_add(B, axe));</div>
<div class="line"> </div>
<div class="line">ns(Monster_end_as_root(B));</div>
</div><!-- fragment --> </div><h1><a class="anchor" id="autotoc_md64"></a>
Basic Reflection</h1>
<p>The C-API does support reading binary schema (.bfbs) files via code generated from the <code>reflection.fbs</code> schema, and an <a href="https://github.com/dvidelabs/flatcc/tree/master/samples/reflection">example usage</a> shows how to use this. The reflection schema files are pre-generated in the <a href="https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection">runtime distribution</a>.</p>
<h1><a class="anchor" id="autotoc_md65"></a>
Mutations and Reflection</h1>
<p>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).</p>
<p>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. <br />
The reflection example makes use of this feature to look up objects by name.</p>
<p>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.</p>
<p>Scalars, structs and strings can be used as source, as well vectors of these.</p>
<p>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.</p>
<h1><a class="anchor" id="autotoc_md66"></a>
Namespaces</h1>
<p>The <code>FLATBUFFERS_WRAP_NAMESPACE</code> 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 <a href="https://github.com/dvidelabs/flatcc/blob/master/samples/reflection/bfbs2json.c">reflection example</a> mentioned above uses this approach.</p>
<h1><a class="anchor" id="autotoc_md67"></a>
Checking for Present Members</h1>
<p>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 <code>mana</code> was set to the default value <code>150</code> and therefore shouldn't be present.</p>
<div class="language-c"> <div class="fragment"><div class="line"><span class="keywordtype">int</span> hp_present = ns(Monster_hp_is_present(monster)); <span class="comment">// 1</span></div>
<div class="line"><span class="keywordtype">int</span> mana_present = ns(Monster_mana_is_present(monster)); <span class="comment">// 0</span></div>
</div><!-- fragment --> </div><h1><a class="anchor" id="autotoc_md68"></a>
Alternative ways to add a Union</h1>
<p>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.</p>
<div class="language-c"> <div class="fragment"><div class="line">ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));</div>
<div class="line">ns(Monster_equipped_add(B, equipped));</div>
<div class="line"><span class="comment">// or alternatively</span></div>
<div class="line">ns(Monster_equipped_Weapon_add(B, axe);</div>
<div class="line"><span class="comment">// or alternatively</span></div>
<div class="line">ns(Monster_equipped_add_type(B, ns(Equipment_Weapon));</div>
<div class="line">ns(Monster_equipped_add_member(B, axe));</div>
</div><!-- fragment --> </div><h1><a class="anchor" id="autotoc_md69"></a>
Why not integrate with the &lt;tt&gt;flatc&lt;/tt&gt; tool?</h1>
<p><a href="https://github.com/dvidelabs/flatcc/issues/1">It was considered how the C code generator could be integrated into the <code>flatc</code> tool</a>, 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 <code>flatcc</code> tool instead of <code>flatc</code> given that the FlatBuffers C runtime library needs to be made available regardless. </p>
</div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- Google Analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-49880327-7', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>