Search code examples
c++cstreamfstream

Using same object to write wide char and char to write to the same file


I have C code that I am trying to convert to C++. To summarize a snippet of the code in C is as follows:

    FILE *fp = fopen("temp.bin", "wb");
    wchar_t* wide_word = _T("wide char");
    char* word = "char";
    fwprintf(fp, _T("%s"), wide_word);
    fprintf(fp, "%s", word);

The advantage in the C case being we can continue using the same fp pointer to print both char and wide char by simple passing the pointer. Can we achieve the same in C++ without needing to initialize to objects ofstream and wofstream to write to the same file and get exact same output as the above C implementation?

I tried the following in C++ (amongst many other things)

    auto os = std::ofstream("temp_cpp.bin", std::ios::binary | std::ios::out);
    wchar_t* wide_word = _T("wide char");
    char* word = "char";
    std::wstring st(wide_word);
    std::string str(st.begin(),st.end());
    os.write(reinterpret_cast<const char*>(str.c_str()), sizeof(str));
    os.write(reinterpret_cast<const char*>(word), sizeof(word));

Solution

  • Yes, you can use the same write function to either write the ANSI bytes or wide char bytes to the file. There are some mistakes in the code. sizeof(str) will return the size of the std::string object, not the length of the string and sizeof(word) will return the size of a pointer, again not the length of the string (although you might be lucky with this one on 32-bit systems where the size of the pointer matches your string length). Further, you are writing ANSI chars two times rather than first writing wide chars and then ANSI chars as you have probably intended following your fprintf example. What you meant to write there was probably:

    auto os = std::ofstream("temp_cpp.bin", std::ios::binary | std::ios::out);
    const wchar_t* wide_word = L"wide char";
    const char* word = "char";
    std::wstring st(wide_word);
    std::string str(st.begin(), st.end());
    os.write((const char*)(st.c_str()), st.length() * sizeof(wchar_t));
    os.write(word, strlen(word));
    

    This should yield the same file content as your fprintf example (but it is not guaranteed as it may depend on setLocale). Or, without the use of std::wstring:

    auto os = std::ofstream("temp_cpp.bin", std::ios::binary | std::ios::out);
    const wchar_t* wide_word = L"wide char";
    const char* word = "char";
    os.write((const char*)wide_word, wcslen(wide_word) * sizeof(wchar_t));
    os.write(word, strlen(word));
    

    Whether it is advisable to write different text encodings into the same file is another question.