-1

I work with flatbuffers and need to write data to file. Flatbuffer struct returns uint8_t*, but std::ofstream::write takes char* as a parameter. Could you tell me which approach using two static_casts or reinterpret_cast better and why?

    flatbuffers::FlatBufferBuilder fbBuilder // flatbuffer structer 
    ... // write something to fbBuilder
    std::ofstream out(filename);
    // this
    out.write(static_cast<const char*>(static_cast<const void*>(fbBuilder.GetBufferPointer())), fbBuilder.GetSize());
    // or this ? 
    out.write(reinterpret_cast<const char*>(fbBuilder.GetBufferPointer())), fbBuilder.GetSize());
  • Voting to close as opinion based. IMO, it's better to be explicit about your intent and use `reinterpret_cast`. Double `static_cast` looks like a workaround for code analyzer that warns about `reinterpret_cast` usages. – Yksisarvinen Mar 16 '20 at 16:57
  • https://stackoverflow.com/questions/60700531/how-could-i-cast-c-const-float-to-char-type – R Sahu Mar 16 '20 at 16:58
  • 1
    `reinterpret_cast` is best avoided. – Ron Mar 16 '20 at 17:03
  • 3
    @Ron, for writing to files and reading from files, `reinterpret_cast` is appropriate. – R Sahu Mar 16 '20 at 17:08
  • 1
    Personally I would use `reinterpret_cast`. There is explicit language in the standard that you can iterate the by of an object when using a `char*` so it's "standard" way to do this. – NathanOliver Mar 16 '20 at 17:12
  • Why casting two times ? Just cast to final type and you are done. – Werner Mar 16 '20 at 19:21

3 Answers3

4

There is no added safety from the static casts in this case: A static cast from void* is equally dangerous as a reinterpret cast. In fact, reinterpret cast is defined in terms of casts through void*, so the examples are effectively identical in all but syntax.

The two static casts are longer and harder to read than the single reinterpret cast.

eerorika
  • 232,697
  • 12
  • 197
  • 326
1

FYI, you don't need to cast to const in this example. GetBufferPointer() returns a non-const uint8_t*, and you can pass a non-const char* to ostream::write(). A pointer-to-non-const can be assigned to a pointer-to-const, the compiler will implicitly apply the const for you. So a single cast will suffice, which in this case would require reinterpret_cast to cast from uint8_t* directly to char*:

out.write(reinterpret_cast<char*>(fbBuilder.GetBufferPointer()), fbBuilder.GetSize());
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

Double static_cast is equivalent to reinterpret_cast:

https://en.cppreference.com/w/cpp/language/reinterpret_cast

5) Any object pointer type T1* can be converted to another object pointer type cv T2*. This is exactly equivalent to static_cast< cv T2*> (static_cast< cv void*> (expression)) (which implies that if T2's alignment requirement is not stricter than T1's, the value of the pointer does not change and conversion of the resulting pointer back to its original type yields the original value). In any case, the resulting pointer may only be dereferenced safely if allowed by the type aliasing rules (see below)

It's idiomatic to use reinterpret_cast in this case, for example, the sample code for ostream::write() uses reinterpret_cast:

https://en.cppreference.com/w/cpp/io/basic_ostream/write

#include <iostream>

int main()
{
    int n = 0x41424344;
    std::cout.write(reinterpret_cast<char*>(&n), sizeof n) << '\n';

    char c[]="This is sample text.";
    std::cout.write(c,4)<<'\n';
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
SPD
  • 370
  • 2
  • 9