| 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: | |
| table mytable(native_custom_alloc:"custom_allocator") { | |
| ... | |
| } | |
| with custom_allocator defined before flatbuffers.h is included, as: | |
| 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: | |
| struct Vec2 { | |
| x: float; | |
| y: float; | |
| } | |
| generates the following Object-Based API class: | |
| 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. | |
| 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. | |
| However, becuase the native_type is unknown to flatbuffers, the user must | |
| provide the following functions to aide in the serialization process: | |
| namespace flatbuffers { | |
| FlatbufferStruct Pack(const native_type& obj); | |
| native_type UnPack(const FlatbufferStruct& obj); | |
| } | |
| Finally, the following top-level attribute | |
| - `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 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 primites. 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> |