| <!-- 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.8.13"/> |
| <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> |
| <script type="text/javascript"> |
| $(document).ready(initResizable); |
| </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.8.13 --> |
| <script type="text/javascript"> |
| var searchBox = new SearchBox("searchBox", "search",false,'Search'); |
| </script> |
| <script type="text/javascript" src="menudata.js"></script> |
| <script type="text/javascript" src="menu.js"></script> |
| <script type="text/javascript"> |
| $(function() { |
| initMenu('',true,false,'search.php','Search'); |
| $(document).ready(function() { init_search(); }); |
| }); |
| </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"> |
| $(document).ready(function(){initNavTree('flatbuffers_guide_use_c.html','');}); |
| </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="header"> |
| <div class="headertitle"> |
| <div class="title">Use in C </div> </div> |
| </div><!--header--> |
| <div class="contents"> |
| <div class="textblock"><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> |
| <h2>General Documention</h2> |
| <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> |
| <h2>Supported Platforms</h2> |
| <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> |
| <h2>Modular Object Creation</h2> |
| <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 = &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, &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> |
| <h2>Top Down Example</h2> |
| <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">"Orc"</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">"Sword"</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">"Axe"</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">"Sword"</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">"Axe"</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><h2>Basic Reflection</h2> |
| <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> |
| <h2>Mutations and Reflection</h2> |
| <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. 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> |
| <h2>Namespaces</h2> |
| <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> |
| <h2>Checking for Present Members</h2> |
| <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><h2>Alternative ways to add a Union</h2> |
| <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><h2>Why not integrate with the <code>flatc</code> tool?</h2> |
| <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><!-- 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> |