3

I am trying to get going with Flatbuffers in C++, but I'm already failing to write and read a struct in a union. I have reduced my original problem to an anonymous, minimal example.

Example Schema (favorite.fbs)

// favorite.fbs
struct FavoriteNumbers
{
    first: uint8;
    second: uint8;
    third: uint8;
}

union Favorite
{ FavoriteNumbers }

table Data
{ favorite: Favorite; }

root_type Data;

I compiled the schema using Flatbuffers 1.11.0 downloaded from the release page (I'm on Windows so to be safe I used the precompiled binaries).

flatc --cpp favorite.fbs

This generates the file favorite_generated.h.

Example Code (fav.cpp)

#include <iostream>
#include "favorite_generated.h"

int main(int, char**)
{
    using namespace flatbuffers;
    FlatBufferBuilder builder;

    // prepare favorite numbers and write them to the buffer
    FavoriteNumbers inFavNums(17, 42, 7);
    auto inFav{builder.CreateStruct(&inFavNums)};
    auto inData{CreateData(builder, Favorite_FavoriteNumbers, inFav.Union())};
    builder.Finish(inData);

    // output original numbers from struct used to write (just to be safe)
    std::cout << "favorite numbers written: "
        << +inFavNums.first() << ", "
        << +inFavNums.second() << ", "
        << +inFavNums.third() << std::endl;

    // output final buffer size
    std::cout << builder.GetSize() << " B written" << std::endl;

    // read from the buffer just created
    auto outData{GetData(builder.GetBufferPointer())};
    auto outFavNums{outData->favorite_as_FavoriteNumbers()};

    // output read numbers
    std::cout << "favorite numbers read: "
        << +outFavNums->first() << ", "
        << +outFavNums->second() << ", "
        << +outFavNums->third() << std::endl;

    return 0;
}

I'm using unary + to force numerical output instead of characters. An answer to another question here on StackOverflow told me I had to use CreateStruct to achieve what I want. I compiled the code using g++ 9.1.0 (by MSYS2).

g++ -std=c++17 -Ilib/flatbuffers/include fav.cpp -o main.exe

This generates the file main.exe.

Output

favorite numbers written: 17, 42, 7
32 B written
favorite numbers read: 189, 253, 34

Obviously this is not the desired outcome. What am I doing wrong?

Neonit
  • 680
  • 8
  • 27
  • it looks like if even there is only one member of union, flatbuffers generate something a tagged union with "NONE" and "FavoriteNumbers" state. – Swift - Friday Pie Sep 26 '19 at 08:43
  • @Swift-FridayPie Yes, it does, but what do you want to tell me with this? – Neonit Sep 26 '19 at 08:46
  • @Marek R why, it is char to int promotion? – Swift - Friday Pie Sep 26 '19 at 08:47
  • @MaxLanghof sory missed that first piece of code is not C/C++ :/. – Marek R Sep 26 '19 at 08:47
  • @Neon not very familiar with flat-buffer syntax usage, but reading source code it uses for headers, it uses reinterpret cast of pointers in outdated belief that address would be same (should be considering alignment, but who knows?) Also seem code is very outdated , e.g. believing that `if()` in template can be equivalent of `if constexpr`. How it behaves if compiled in C++11? If compiled with strict aliasing off? – Swift - Friday Pie Sep 26 '19 at 09:02
  • Can you provide the generated *"favorite_generated.h"* as well? Also I can't find `CreateData` or `GetData` anywhere in the flatbuffers github repo. Now this might be an issue with how search works on github, or this might be because these methods are your implementations, or they might be part of the generated code. Either way, can you make your example a full [MCVE]? – Max Vollmer Sep 26 '19 at 09:08
  • @Swift-FridayPie I compiled it now using `g++ -std=c++11 -fno-strict-aliasing -Ilib/flatbuffers/include fav.cpp -o main.exe` and get the same output. – Neonit Sep 26 '19 at 09:09
  • @MaxVollmer those are generated – Swift - Friday Pie Sep 26 '19 at 09:10
  • @MaxVollmer Yes, `CreateData` and `GetData` are generated from the `favorite.fbs` by `flatc`. I've put it on gist: https://gist.github.com/Neonit/5037aa6613a68c760cdaca7427c3d8b1 I wasn't sure, if I should add this wall of code to my post inline and I'm still not sure now, that's why I put it on gist instead. After all, it can be reproduced using the commands I've posted and the tools I've linked. But surely for quickly browsing and reconstructing an upload is useful. – Neonit Sep 26 '19 at 09:11
  • Yeah that might be too long, especially since it's generated and you have included the source file for the generator. However it seems that they covered alignment of `FavoriteNumbers`, looking at the declaration of `FavoriteNumbers` and the definition of `FLATBUFFERS_MANUALLY_ALIGNED_STRUCT` [here](https://github.com/google/flatbuffers/blob/master/include/flatbuffers/flatbuffers.h), **but not** for `Data`. I would file a bug report. – Max Vollmer Sep 26 '19 at 09:23

1 Answers1

1

Remove the & in front of inFavNums and it will work.

CreateStruct is a template function, which sadly in this case it means it will also take pointers without complaining about it. Would be nice to avoid that, but that isn't that easy in C++.

Aardappel
  • 5,559
  • 1
  • 19
  • 22