| Use in C++ {#flatbuffers_guide_use_cpp} |
| ========== |
| |
| ## Before you get started |
| |
| Before diving into the FlatBuffers usage in C++, it should be noted that |
| the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide |
| to general FlatBuffers usage in all of the supported languages (including C++). |
| This page is designed to cover the nuances of FlatBuffers usage, specific to |
| C++. |
| |
| #### Prerequisites |
| |
| This page assumes you have written a FlatBuffers schema and compiled it |
| with the Schema Compiler. If you have not, please see |
| [Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) |
| and [Writing a schema](@ref flatbuffers_guide_writing_schema). |
| |
| Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't |
| matter), you've generated a C++ header called `mygame_generated.h` using the |
| compiler (e.g. `flatc -c mygame.fbs`), you can now start using this in |
| your program by including the header. As noted, this header relies on |
| `flatbuffers/flatbuffers.h`, which should be in your include path. |
| |
| ## FlatBuffers C++ library code location |
| |
| The code for the FlatBuffers C++ library can be found at |
| `flatbuffers/include/flatbuffers`. You can browse the library code on the |
| [FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/include/flatbuffers). |
| |
| ## Testing the FlatBuffers C++ library |
| |
| The code to test the C++ library can be found at `flatbuffers/tests`. |
| The test code itself is located in |
| [test.cpp](https://github.com/google/flatbuffers/blob/master/tests/test.cpp). |
| |
| This test file is built alongside `flatc`. To review how to build the project, |
| please read the [Building](@ref flatbuffers_guide_building) documentation. |
| |
| To run the tests, execute `flattests` from the root `flatbuffers/` directory. |
| For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply |
| run: `./flattests`. |
| |
| ## Using the FlatBuffers C++ library |
| |
| *Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth |
| example of how to use FlatBuffers in C++.* |
| |
| FlatBuffers supports both reading and writing FlatBuffers in C++. |
| |
| To use FlatBuffers in your code, first generate the C++ classes from your |
| schema with the `--cpp` option to `flatc`. Then you can include both FlatBuffers |
| and the generated code to read or write FlatBuffers. |
| |
| For example, here is how you would read a FlatBuffer binary file in C++: |
| First, include the library and generated code. Then read the file into |
| a `char *` array, which you pass to `GetMonster()`. |
| |
| ```cpp |
| #include "flatbuffers/flatbuffers.h" |
| #include "monster_test_generate.h" |
| #include <iostream> // C++ header file for printing |
| #include <fstream> // C++ header file for file access |
| |
| |
| std::ifstream infile; |
| infile.open("monsterdata_test.mon", std::ios::binary | std::ios::in); |
| infile.seekg(0,std::ios::end); |
| int length = infile.tellg(); |
| infile.seekg(0,std::ios::beg); |
| char *data = new char[length]; |
| infile.read(data, length); |
| infile.close(); |
| |
| auto monster = GetMonster(data); |
| ``` |
| |
| `monster` is of type `Monster *`, and points to somewhere *inside* your |
| buffer (root object pointers are not the same as `buffer_pointer` \!). |
| If you look in your generated header, you'll see it has |
| convenient accessors for all fields, e.g. `hp()`, `mana()`, etc: |
| |
| ```cpp |
| std::cout << "hp : " << monster->hp() << std::endl; // '80' |
| std::cout << "mana : " << monster->mana() << std::endl; // default value of '150' |
| std::cout << "name : " << monster->name()->c_str() << std::endl; // "MyMonster" |
| ``` |
| |
| *Note: That we never stored a `mana` value, so it will return the default.* |
| |
| The following attributes are supported: |
| |
| - `shared` (on a field): For string fields, this enables the usage of string |
| pooling (i.e. `CreateSharedString`) as default serialization behavior. |
| |
| Specifically, `CreateXxxDirect` functions and `Pack` functions for object |
| based API (see below) will use `CreateSharedString` to create strings. |
| |
| ## Object based API {#flatbuffers_cpp_object_based_api} |
| |
| FlatBuffers is all about memory efficiency, which is why its base API is written |
| around using as little as possible of it. This does make the API clumsier |
| (requiring pre-order construction of all data, and making mutation harder). |
| |
| For times when efficiency is less important a more convenient object based API |
| can be used (through `--gen-object-api`) that is able to unpack & pack a |
| FlatBuffer into objects and standard STL containers, allowing for convenient |
| construction, access and mutation. |
| |
| To use: |
| |
| ```cpp |
| // Autogenerated class from table Monster. |
| MonsterT monsterobj; |
| |
| // Deserialize from buffer into object. |
| GetMonster(flatbuffer)->UnPackTo(&monsterobj); |
| |
| // Update object directly like a C++ class instance. |
| cout << monsterobj.name; // This is now a std::string! |
| monsterobj.name = "Bob"; // Change the name. |
| |
| // Serialize into new flatbuffer. |
| FlatBufferBuilder fbb; |
| fbb.Finish(Monster::Pack(fbb, &monsterobj)); |
| ``` |
| |
| The following attributes are specific to the object-based API code generation: |
| |
| - `native_inline` (on a field): Because FlatBuffer tables and structs are |
| optionally present in a given buffer, they are best represented as pointers |
| (specifically std::unique_ptrs) in the native class since they can be null. |
| This attribute changes the member declaration to use the type directly |
| rather than wrapped in a unique_ptr. |
| |
| - `native_default("value")` (on a field): For members that are declared |
| "native_inline", the value specified with this attribute will be included |
| verbatim in the class constructor initializer list for this member. |
| |
| - `native_custom_alloc("custom_allocator")` (on a table or struct): When using the |
| object-based API all generated NativeTables that are allocated when unpacking |
| your flatbuffer will use "custom allocator". The allocator is also used by |
| any std::vector that appears in a table defined with `native_custom_alloc`. |
| This can be used to provide allocation from a pool for example, for faster |
| unpacking when using the object-based API. |
| |
| Minimal Example: |
| |
| schema: |
| |
| ```cpp |
| table mytable(native_custom_alloc:"custom_allocator") { |
| ... |
| } |
| ``` |
| |
| with `custom_allocator` defined before `flatbuffers.h` is included, as: |
| |
| ```cpp |
| template <typename T> struct custom_allocator : public std::allocator<T> { |
| |
| typedef T *pointer; |
| |
| template <class U> |
| struct rebind { |
| typedef custom_allocator<U> other; |
| }; |
| |
| pointer allocate(const std::size_t n) { |
| return std::allocator<T>::allocate(n); |
| } |
| |
| void deallocate(T* ptr, std::size_t n) { |
| return std::allocator<T>::deallocate(ptr,n); |
| } |
| |
| custom_allocator() throw() {} |
| |
| template <class U> |
| custom_allocator(const custom_allocator<U>&) throw() {} |
| }; |
| ``` |
| |
| - `native_type("type")` (on a struct): In some cases, a more optimal C++ data |
| type exists for a given struct. For example, the following schema: |
| |
| ```cpp |
| struct Vec2 { |
| x: float; |
| y: float; |
| } |
| ``` |
| |
| generates the following Object-Based API class: |
| |
| ```cpp |
| struct Vec2T : flatbuffers::NativeTable { |
| float x; |
| float y; |
| }; |
| ``` |
| |
| However, it can be useful to instead use a user-defined C++ type since it |
| can provide more functionality, eg. |
| |
| ```cpp |
| struct vector2 { |
| float x = 0, y = 0; |
| vector2 operator+(vector2 rhs) const { ... } |
| vector2 operator-(vector2 rhs) const { ... } |
| float length() const { ... } |
| // etc. |
| }; |
| ``` |
| |
| The `native_type` attribute will replace the usage of the generated class |
| with the given type. So, continuing with the example, the generated |
| code would use `vector2` in place of `Vec2T` for all generated code of |
| the Object-Based API. |
| |
| However, because the `native_type` is unknown to flatbuffers, the user must |
| provide the following functions to aide in the serialization process: |
| |
| ```cpp |
| namespace flatbuffers { |
| Vec2 Pack(const vector2& obj); |
| vector2 UnPack(const Vec2& obj); |
| } |
| ``` |
| |
| - `native_type_pack_name("name")` (on a struct when `native_type` is |
| specified, too): when you want to use the same `native_type` multiple times |
| (e. g. with different precision) you must make the names of the Pack/UnPack |
| functions unique, otherwise you will run into compile errors. This attribute |
| appends a name to the expected Pack/UnPack functions. So when you |
| specify `native_type_pack_name("Vec2")` in the above example you now need to |
| implement these serialization functions instead: |
| |
| ```cpp |
| namespace flatbuffers { |
| Vec2 PackVec2(const vector2& obj); |
| vector2 UnPackVec2(const Vec2& obj); |
| } |
| ``` |
| |
| Finally, the following top-level attributes: |
| |
| - `native_include("path")` (at file level): Because the `native_type` attribute |
| can be used to introduce types that are unknown to flatbuffers, it may be |
| necessary to include "external" header files in the generated code. This |
| attribute can be used to directly add an #include directive to the top of |
| the generated code that includes the specified path directly. |
| |
| - `force_align`: this attribute may not be respected in the object API, |
| depending on the aligned of the allocator used with `new`. |
| |
| # External references |
| |
| An additional feature of the object API is the ability to allow you to load |
| multiple independent FlatBuffers, and have them refer to eachothers objects |
| using hashes which are then represented as typed pointers in the object API. |
| |
| To make this work have a field in the objects you want to referred to which is |
| using the string hashing feature (see `hash` attribute in the |
| [schema](@ref flatbuffers_guide_writing_schema) documentation). Then you have |
| a similar hash in the field referring to it, along with a `cpp_type` |
| attribute specifying the C++ type this will refer to (this can be any C++ |
| type, and will get a `*` added). |
| |
| Then, in JSON or however you create these buffers, make sure they use the |
| same string (or hash). |
| |
| When you call `UnPack` (or `Create`), you'll need a function that maps from |
| hash to the object (see `resolver_function_t` for details). |
| |
| # Using different pointer types |
| |
| By default the object tree is built out of `std::unique_ptr`, but you can |
| influence this either globally (using the `--cpp-ptr-type` argument to |
| `flatc`) or per field (using the `cpp_ptr_type` attribute) to by any smart |
| pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *` |
| pointers. Unlike the smart pointers, naked pointers do not manage memory for |
| you, so you'll have to manage their lifecycles manually. To reference the |
| pointer type specified by the `--cpp-ptr-type` argument to `flatc` from a |
| flatbuffer field set the `cpp_ptr_type` attribute to `default_ptr_type`. |
| |
| # Using different string type |
| |
| By default the object tree is built out of `std::string`, but you can |
| influence this either globally (using the `--cpp-str-type` argument to |
| `flatc`) or per field using the `cpp_str_type` attribute. |
| |
| The type must support `T::c_str()`, `T::length()` and `T::empty()` as member functions. |
| |
| Further, the type must be constructible from std::string, as by default a |
| std::string instance is constructed and then used to initialize the custom |
| string type. This behavior impedes efficient and zero-copy construction of |
| custom string types; the `--cpp-str-flex-ctor` argument to `flatc` or the |
| per field attribute `cpp_str_flex_ctor` can be used to change this behavior, |
| so that the custom string type is constructed by passing the pointer and |
| length of the FlatBuffers String. The custom string class will require a |
| constructor in the following format: `custom_str_class(const char *, size_t)`. |
| Please note that the character array is not guaranteed to be NULL terminated, |
| you should always use the provided size to determine end of string. |
| |
| ## Reflection (& Resizing) |
| |
| There is experimental support for reflection in FlatBuffers, allowing you to |
| read and write data even if you don't know the exact format of a buffer, and |
| even allows you to change sizes of strings and vectors in-place. |
| |
| The way this works is very elegant; there is actually a FlatBuffer schema that |
| describes schemas (\!) which you can find in `reflection/reflection.fbs`. |
| The compiler, `flatc`, can write out any schemas it has just parsed as a binary |
| FlatBuffer, corresponding to this meta-schema. |
| |
| Loading in one of these binary schemas at runtime allows you traverse any |
| FlatBuffer data that corresponds to it without knowing the exact format. You |
| can query what fields are present, and then read/write them after. |
| |
| For convenient field manipulation, you can include the header |
| `flatbuffers/reflection.h` which includes both the generated code from the meta |
| schema, as well as a lot of helper functions. |
| |
| And example of usage, for the time being, can be found in |
| `test.cpp/ReflectionTest()`. |
| |
| ## Mini Reflection |
| |
| A more limited form of reflection is available for direct inclusion in |
| generated code, which doesn't do any (binary) schema access at all. It was designed |
| to keep the overhead of reflection as low as possible (on the order of 2-6 |
| bytes per field added to your executable), but doesn't contain all the |
| information the (binary) schema contains. |
| |
| You add this information to your generated code by specifying `--reflect-types` |
| (or instead `--reflect-names` if you also want field / enum names). |
| |
| You can now use this information, for example to print a FlatBuffer to text: |
| |
| auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable()); |
| |
| `MonsterTypeTable()` is declared in the generated code for each type. The |
| string produced is very similar to the JSON produced by the `Parser` based |
| text generator. |
| |
| You'll need `flatbuffers/minireflect.h` for this functionality. In there is also |
| a convenient visitor/iterator so you can write your own output / functionality |
| based on the mini reflection tables without having to know the FlatBuffers or |
| reflection encoding. |
| |
| ## Storing maps / dictionaries in a FlatBuffer |
| |
| FlatBuffers doesn't support maps natively, but there is support to |
| emulate their behavior with vectors and binary search, which means you |
| can have fast lookups directly from a FlatBuffer without having to unpack |
| your data into a `std::map` or similar. |
| |
| To use it: |
| - Designate one of the fields in a table as they "key" field. You do this |
| by setting the `key` attribute on this field, e.g. |
| `name:string (key)`. |
| You may only have one key field, and it must be of string or scalar type. |
| - Write out tables of this type as usual, collect their offsets in an |
| array or vector. |
| - Instead of `CreateVector`, call `CreateVectorOfSortedTables`, |
| which will first sort all offsets such that the tables they refer to |
| are sorted by the key field, then serialize it. |
| - Now when you're accessing the FlatBuffer, you can use `Vector::LookupByKey` |
| instead of just `Vector::Get` to access elements of the vector, e.g.: |
| `myvector->LookupByKey("Fred")`, which returns a pointer to the |
| corresponding table type, or `nullptr` if not found. |
| `LookupByKey` performs a binary search, so should have a similar speed to |
| `std::map`, though may be faster because of better caching. `LookupByKey` |
| only works if the vector has been sorted, it will likely not find elements |
| if it hasn't been sorted. |
| |
| ## Direct memory access |
| |
| As you can see from the above examples, all elements in a buffer are |
| accessed through generated accessors. This is because everything is |
| stored in little endian format on all platforms (the accessor |
| performs a swap operation on big endian machines), and also because |
| the layout of things is generally not known to the user. |
| |
| For structs, layout is deterministic and guaranteed to be the same |
| across platforms (scalars are aligned to their |
| own size, and structs themselves to their largest member), and you |
| are allowed to access this memory directly by using `sizeof()` and |
| `memcpy` on the pointer to a struct, or even an array of structs. |
| |
| To compute offsets to sub-elements of a struct, make sure they |
| are a structs themselves, as then you can use the pointers to |
| figure out the offset without having to hardcode it. This is |
| handy for use of arrays of structs with calls like `glVertexAttribPointer` |
| in OpenGL or similar APIs. |
| |
| It is important to note is that structs are still little endian on all |
| machines, so only use tricks like this if you can guarantee you're not |
| shipping on a big endian machine (an `assert(FLATBUFFERS_LITTLEENDIAN)` |
| would be wise). |
| |
| ## Access of untrusted buffers |
| |
| The generated accessor functions access fields over offsets, which is |
| very quick. These offsets are not verified at run-time, so a malformed |
| buffer could cause a program to crash by accessing random memory. |
| |
| When you're processing large amounts of data from a source you know (e.g. |
| your own generated data on disk), this is acceptable, but when reading |
| data from the network that can potentially have been modified by an |
| attacker, this is undesirable. |
| |
| For this reason, you can optionally use a buffer verifier before you |
| access the data. This verifier will check all offsets, all sizes of |
| fields, and null termination of strings to ensure that when a buffer |
| is accessed, all reads will end up inside the buffer. |
| |
| Each root type will have a verification function generated for it, |
| e.g. for `Monster`, you can call: |
| |
| ```cpp |
| bool ok = VerifyMonsterBuffer(Verifier(buf, len)); |
| ``` |
| |
| if `ok` is true, the buffer is safe to read. |
| |
| Besides untrusted data, this function may be useful to call in debug |
| mode, as extra insurance against data being corrupted somewhere along |
| the way. |
| |
| While verifying a buffer isn't "free", it is typically faster than |
| a full traversal (since any scalar data is not actually touched), |
| and since it may cause the buffer to be brought into cache before |
| reading, the actual overhead may be even lower than expected. |
| |
| In specialized cases where a denial of service attack is possible, |
| the verifier has two additional constructor arguments that allow |
| you to limit the nesting depth and total amount of tables the |
| verifier may encounter before declaring the buffer malformed. The default is |
| `Verifier(buf, len, 64 /* max depth */, 1000000, /* max tables */)` which |
| should be sufficient for most uses. |
| |
| ## Text & schema parsing |
| |
| Using binary buffers with the generated header provides a super low |
| overhead use of FlatBuffer data. There are, however, times when you want |
| to use text formats, for example because it interacts better with source |
| control, or you want to give your users easy access to data. |
| |
| Another reason might be that you already have a lot of data in JSON |
| format, or a tool that generates JSON, and if you can write a schema for |
| it, this will provide you an easy way to use that data directly. |
| |
| (see the schema documentation for some specifics on the JSON format |
| accepted). |
| |
| Schema evolution compatibility for the JSON format follows the same rules as the binary format (JSON formatted data will be forwards/backwards compatible with schemas that evolve in a compatible way). |
| |
| There are two ways to use text formats: |
| |
| #### Using the compiler as a conversion tool |
| |
| This is the preferred path, as it doesn't require you to add any new |
| code to your program, and is maximally efficient since you can ship with |
| binary data. The disadvantage is that it is an extra step for your |
| users/developers to perform, though you might be able to automate it. |
| |
| flatc -b myschema.fbs mydata.json |
| |
| This will generate the binary file `mydata_wire.bin` which can be loaded |
| as before. |
| |
| #### Making your program capable of loading text directly |
| |
| This gives you maximum flexibility. You could even opt to support both, |
| i.e. check for both files, and regenerate the binary from text when |
| required, otherwise just load the binary. |
| |
| This option is currently only available for C++, or Java through JNI. |
| |
| As mentioned in the section "Building" above, this technique requires |
| you to link a few more files into your program, and you'll want to include |
| `flatbuffers/idl.h`. |
| |
| Load text (either a schema or json) into an in-memory buffer (there is a |
| convenient `LoadFile()` utility function in `flatbuffers/util.h` if you |
| wish). Construct a parser: |
| |
| ```cpp |
| flatbuffers::Parser parser; |
| ``` |
| |
| Now you can parse any number of text files in sequence: |
| |
| ```cpp |
| parser.Parse(text_file.c_str()); |
| ``` |
| |
| This works similarly to how the command-line compiler works: a sequence |
| of files parsed by the same `Parser` object allow later files to |
| reference definitions in earlier files. Typically this means you first |
| load a schema file (which populates `Parser` with definitions), followed |
| by one or more JSON files. |
| |
| As optional argument to `Parse`, you may specify a null-terminated list of |
| include paths. If not specified, any include statements try to resolve from |
| the current directory. |
| |
| If there were any parsing errors, `Parse` will return `false`, and |
| `Parser::error_` contains a human readable error string with a line number |
| etc, which you should present to the creator of that file. |
| |
| After each JSON file, the `Parser::fbb` member variable is the |
| `FlatBufferBuilder` that contains the binary buffer version of that |
| file, that you can access as described above. |
| |
| `samples/sample_text.cpp` is a code sample showing the above operations. |
| |
| ## Threading |
| |
| Reading a FlatBuffer does not touch any memory outside the original buffer, |
| and is entirely read-only (all const), so is safe to access from multiple |
| threads even without synchronisation primitives. |
| |
| Creating a FlatBuffer is not thread safe. All state related to building |
| a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory |
| outside of it is touched. To make this thread safe, either do not |
| share instances of FlatBufferBuilder between threads (recommended), or |
| manually wrap it in synchronisation primitives. There's no automatic way to |
| accomplish this, by design, as we feel multithreaded construction |
| of a single buffer will be rare, and synchronisation overhead would be costly. |
| |
| ## Advanced union features |
| |
| The C++ implementation currently supports vectors of unions (i.e. you can |
| declare a field as `[T]` where `T` is a union type instead of a table type). It |
| also supports structs and strings in unions, besides tables. |
| |
| For an example of these features, see `tests/union_vector`, and |
| `UnionVectorTest` in `test.cpp`. |
| |
| Since these features haven't been ported to other languages yet, if you |
| choose to use them, you won't be able to use these buffers in other languages |
| (`flatc` will refuse to compile a schema that uses these features). |
| |
| These features reduce the amount of "table wrapping" that was previously |
| needed to use unions. |
| |
| To use scalars, simply wrap them in a struct. |
| |
| ## Depth limit of nested objects and stack-overflow control |
| The parser of Flatbuffers schema or json-files is kind of recursive parser. |
| To avoid stack-overflow problem the parser has a built-in limiter of |
| recursion depth. Number of nested declarations in a schema or number of |
| nested json-objects is limited. By default, this depth limit set to `64`. |
| It is possible to override this limit with `FLATBUFFERS_MAX_PARSING_DEPTH` |
| definition. This definition can be helpful for testing purposes or embedded |
| applications. For details see [build](@ref flatbuffers_guide_building) of |
| CMake-based projects. |
| |
| ## Dependence from C-locale {#flatbuffers_locale_cpp} |
| The Flatbuffers [grammar](@ref flatbuffers grammar) uses ASCII |
| character set for identifiers, alphanumeric literals, reserved words. |
| |
| Internal implementation of the Flatbuffers depends from functions which |
| depend from C-locale: `strtod()` or `strtof()`, for example. |
| The library expects the dot `.` symbol as the separator of an integer |
| part from the fractional part of a float number. |
| Another separator symbols (`,` for example) will break the compatibility |
| and may lead to an error while parsing a Flatbuffers schema or a json file. |
| |
| The Standard C locale is a global resource, there is only one locale for |
| the entire application. Some modern compilers and platforms have |
| locale-independent or locale-narrow functions `strtof_l`, `strtod_l`, |
| `strtoll_l`, `strtoull_l` to resolve this dependency. |
| These functions use specified locale rather than the global or per-thread |
| locale instead. They are part of POSIX-2008 but not part of the C/C++ |
| standard library, therefore, may be missing on some platforms. |
| The Flatbuffers library try to detect these functions at configuration and |
| compile time: |
| - CMake `"CMakeLists.txt"`: |
| - Check existence of `strtol_l` and `strtod_l` in the `<stdlib.h>`. |
| - Compile-time `"/include/base.h"`: |
| - `_MSC_VER >= 1900`: MSVC2012 or higher if build with MSVC. |
| - `_XOPEN_SOURCE>=700`: POSIX-2008 if build with GCC/Clang. |
| |
| After detection, the definition `FLATBUFFERS_LOCALE_INDEPENDENT` will be |
| set to `0` or `1`. |
| To override or stop this detection use CMake `-DFLATBUFFERS_LOCALE_INDEPENDENT={0|1}` |
| or predefine `FLATBUFFERS_LOCALE_INDEPENDENT` symbol. |
| |
| To test the compatibility of the Flatbuffers library with |
| a specific locale use the environment variable `FLATBUFFERS_TEST_LOCALE`: |
| ```sh |
| >FLATBUFFERS_TEST_LOCALE="" ./flattests |
| >FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./flattests |
| ``` |
| |
| ## Support of floating-point numbers |
| The Flatbuffers library assumes that a C++ compiler and a CPU are |
| compatible with the `IEEE-754` floating-point standard. |
| The schema and json parser may fail if `fast-math` or `/fp:fast` mode is active. |
| |
| ### Support of hexadecimal and special floating-point numbers |
| According to the [grammar](@ref flatbuffers_grammar) `fbs` and `json` files |
| may use hexadecimal and special (`NaN`, `Inf`) floating-point literals. |
| The Flatbuffers uses `strtof` and `strtod` functions to parse floating-point |
| literals. The Flatbuffers library has a code to detect a compiler compatibility |
| with the literals. If necessary conditions are met the preprocessor constant |
| `FLATBUFFERS_HAS_NEW_STRTOD` will be set to `1`. |
| The support of floating-point literals will be limited at compile time |
| if `FLATBUFFERS_HAS_NEW_STRTOD` constant is less than `1`. |
| In this case, schemas with hexadecimal or special literals cannot be used. |
| |
| ### Comparison of floating-point NaN values |
| The floating-point `NaN` (`not a number`) is special value which |
| representing an undefined or unrepresentable value. |
| `NaN` may be explicitly assigned to variables, typically as a representation |
| for missing values or may be a result of a mathematical operation. |
| The `IEEE-754` defines two kind of `NaNs`: |
| - Quiet NaNs, or `qNaNs`. |
| - Signaling NaNs, or `sNaNs`. |
| |
| According to the `IEEE-754`, a comparison with `NaN` always returns |
| an unordered result even when compared with itself. As a result, a whole |
| Flatbuffers object will be not equal to itself if has one or more `NaN`. |
| Flatbuffers scalar fields that have the default value are not actually stored |
| in the serialized data but are generated in code (see [Writing a schema](@ref flatbuffers_guide_writing_schema)). |
| Scalar fields with `NaN` defaults break this behavior. |
| If a schema has a lot of `NaN` defaults the Flatbuffers can override |
| the unordered comparison by the ordered: `(NaN==NaN)->true`. |
| This ordered comparison is enabled when compiling a program with the symbol |
| `FLATBUFFERS_NAN_DEFAULTS` defined. |
| Additional computations added by `FLATBUFFERS_NAN_DEFAULTS` are very cheap |
| if GCC or Clang used. These compilers have a compile-time implementation |
| of `isnan` checking which MSVC does not. |
| |
| <br> |