My opinion, not necessarily right, just for your reference. 😄
Overview
- cout/wcout is the concept of the C++ world, the equivalence terms of C world is printf/wrpintf. These mechanisms are used to transfer our content that we provide in application into the standard output stream.
- Compatible with C language is one of the C++' design objective. That is to say, the C++'s implementation must guarantee the mixing of C++ and C code execute correctly.
- The problem is obvious, C and C++ are two different languages, after all. The C++'s cout/wcout and C's printf/wprintf have their own implementation, such as their own application layer buffer, their own flush strategy of the buffer, their own locale dependency ... At a word, cout/wcout and printf/wprintf are two separate operating mechanisms, simple mixing can lead to unexpected results, so the C++ standard designer must develop a workable solution.
- From the coder's point of view, the correct behavior of mixing cout and printf should be guaranteed the execute result as like as just use cout or printf. To achieve this effect, the concept of sync with stdio is put forward. In my opinion, the 'stdio' refer in particular to the C language's I/O mechanism, printf/wprintf belong to it. So 'sync to stdio' means sync C++'s I/O mechanism to C's mechanism. We can use the method
std::ios::sync_with_stdio
to enable/disable the sync, it is enabled by default.
- So, what is 'sync' indeed ? how to sync to stdio ? It depends on the implementation, I do not know the details. It seems that the 'sync' concept is more like 'share', the buffer of printf/wprintf shared with cout/wcout. Or the cout/wcout use print/wprintf's buffer directly. In brief, if we enable 'sync', the cout/wcout is no longer independent, typically the buffer, it depend on C stdio. The 'sync' makes the I/O process of C++ and C just like one language.
- Therefore, we can use cout+printf or wcout+wprintf at ease in C++ code by enable sync with stdio (it's enabled by default, we don't need to operate). This problem is solved by 'sync'. The another puzzle is mix cout+wcout or mix printf+wprintf, is that ok ? -- this topic discuss below .
cout
printf
work on the char
storage unit, and wcout
wprintf
work on wchar_t
. Mixed use cout+wcout or printf+wprintf do not involve language level conflict. Because the cout
wcout
belong to same language, so do the printf
and wprintf
. The crux of the question here is 'the orientation of the standard output stream'
.
- What is the orientation mean? It can be interpreted as granularity i think. As we know, the OOD is object orientated design, that means the granularity of design is object. Another example is byte stream orientated protocol - TCP, that means we must concern the byte if we construct application based on TCP. Get in back to the point, so... what is the orientation of the standard output stream ? The answer is
byte
or wide byte
or something else i don't confirm ...
- The standard output stream either byte-oriented or wide byte-oriented, and how does the C++/C language determine which one? The strategy is to see the first executed I/O function/method's version, if it is the byte version, just like cout or printf, then the standard output stream is set to byte-oriented, else if it is the wide byte version, like wcout or wprintf, then the standard output stream is wide byte-oriented.
- Why should we care the standard output stream oriented? That's because the different orientation of the standard output stream will affect the presentation of the content. It's easy to think of it this way, the orientation decide the granularity of the standard output stream to process/extract/translate the content from cout/wcout/printf/wprintf. Just think that, we first use wcout to trigger the standard output stream be set to wide byte-oriented, then we provide some content by cout, the result is the wide byte-oriented standard output stream received a group of content processed by byte, finally the content print to the device which connected to the standard output stream is undefined.
- In addition, in my actual development, there's another situation of standard output stream orientation, i've discovered. After disable the sync witch stdio -
std::ios::sync_with_stdio(false)
, no matter i call wcout then cout or call cout then wcout, the print content is all ok!(Of course, we must to set locale, but that's another topic). In this condition, i call fwide(stdout, 0)
always return 0, that means the current standard output stream orientation is undecided, is the undecided state due to standard output stream can auto switch to suitable orientation? Or undecided means standard output stream in omnipotent state ? i don't know ...
- A special case. There is a function called
_setmode
provided in Windows world, This function use for set the specific stream's translate mode. After my attempt, i guess the so called 'translate mode' is equivalent to the stream orientation. But, to use the _setmode
set stream orientation seems to set some nonstandard flag value in underlying! Because after i call _setmode
to set certain modes(e.g. _O_WTEXT, _O_U8TEXT, _O_U16TEXT ... ), if i call fwide
try to check current stream orientation, the crash will happen. Perhaps an unintelligible data was queried by fwide
, so it crashed!
Some demos
I write a function checkStdoutOrientation
to get standard output stream orientation
void checkStdoutOrientation()
{
std::fstream fs("result.txt", std::ios::app);
int ret = fwide(stdout, 0);
if (ret > 0) {
fs << "wide byte oriented\n";
} else if (ret < 0) {
fs << "byte oriented\n";
} else {
fs << "undecided oriented\n";
}
fs.close();
}
Demo01: first call wcout, then call cout
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
checkStdoutOrientation();
std::wcout << "456" << std::endl;
checkStdoutOrientation();
std::cout << "123" << std::endl;
checkStdoutOrientation();
return 0;
}
debian10 buster + gcc 8.3.0
Output:

result.txt:

My understanding:
- wcout is first called, so standard output stream is wide byte oriented;
- just because the above situation, content processed by cout cannot be processed by standard output stream, so the "123" cannot print;
Win10 + vs2022
Output:

result.txt:

My understanding:
- it seems that, the windows is not conforming to standards, the standard output stream is always undecided oriented;
- just because the undecided oriented of the standard output stream, all content is print.
Demo02: first call cout, then call wcout
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
checkStdoutOrientation();
std::cout << "123" << std::endl;
checkStdoutOrientation();
std::wcout << "456" << std::endl;
checkStdoutOrientation();
return 0;
}
debian10 buster + gcc 8.3.0
Output:

result.txt:

My understanding:
- cout is first called, so standard output stream is byte oriented;
- because byte is a smaller granularity than wide byte, so wcout content to byte oriented standard output stream can finally print to console.
Win10 + vs2022
Output:

result.txt:

My understanding:
- the standard output stream is always undecided oriented;
- so all content is print.
Demo03: first call wprintf, then call printf
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
checkStdoutOrientation();
wprintf(L"456\n");
checkStdoutOrientation();
printf("123\n");
checkStdoutOrientation();
return 0;
}
It's the same conclusion as Demo01
Demo04: first call printf, then call wprintf
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
checkStdoutOrientation();
printf("123\n");
checkStdoutOrientation();
wprintf(L"456\n");
checkStdoutOrientation();
return 0;
}
debian10 buster + gcc 8.3.0
Output:

result.txt:

My understanding:
- cout is first called, so standard output stream is byte oriented;
- the result is different from Demo02, i don't know why the "456" not show.
Win10 + vs2022
Output:

result.txt:

My understanding:
- the same result as Demo02 .
Demo05: disable sync with stdio, then wcout, cout
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
std::ios::sync_with_stdio(false);
checkStdoutOrientation();
std::wcout << "456" << std::endl;
checkStdoutOrientation();
std::cout << "123" << std::endl;
checkStdoutOrientation();
return 0;
}
debian10 buster + gcc 8.3.0
Output:

result.txt:

My understanding:
- after disabled sync with stdio, the standard output stream is always undecided oriented;
- so all content can print.
Win10 + vs2022
Output:

result.txt:

My understanding:
- the same result as Demo01 .
Demo06: mix cout, printf
#include <cstdio>
#include <iostream>
int main()
{
printf("1\n");
std::cout << "2\n";
printf("3\n");
std::cout << "4\n";
printf("5\n");
printf("\n");
std::ios::sync_with_stdio(false);
printf("1\n");
std::cout << "2\n";
printf("3\n");
std::cout << "4\n";
printf("5\n");
return 0;
}
debian10 buster + gcc 8.3.0
Output:

My understanding:
- sync with stdio is enabled default, so mix cout and printf worked as just call cout or printf.
- after disabled sync with stdio, cout will worked independent, cout and printf do their own thing, so the print content is out of order.
Win10 + vs2022
Output:

My understanding:
- Windows is still so special, no matter disable sync with stdio or not, the mix cout and printf worked as just call cout or printf.
Demo07: print Non-ASCII Characters -- Method A
#include <cstdio>
#include <iostream>
int main()
{
std::locale myloc("en_US.UTF-8");
std::locale::global(myloc); // this setting does not affect wcout
std::wcout << L"漢字\n";
wprintf(L"漢字\n");
return 0;
}
debian10 buster + gcc 8.3.0
Output:

My understanding:
- set global locale does not affect wcout, this wcout's locale is still C locale. It is because the wcout is an object, its locale has already set when object constructed.
- so in that case, why wcout can print the content? don't forget the C++'s iostream is default sync with the stdio, we can simply think that, the wcout work on stdio's buffer, and the stdio is already set to en_US.UTF-8 by the
global(myloc)
code.
Win10 + vs2022
Output:

My understanding:
Demo08: print Non-ASCII Characters -- Method B
#include <cstdio>
#include <iostream>
int main()
{
std::ios::sync_with_stdio(false);
std::locale myloc("en_US.UTF-8");
// std::locale::global(myloc);
std::wcout.imbue(myloc);
std::wcout << "wcout> " << L"漢字\n";
wprintf(L"wprintf> 漢字\n");
return 0;
}
debian10 buster + gcc 8.3.0
Output:

My understanding:
- due to disabled sync to stdio, the wprintf and wcout work separately, so print out of order;
- Still due to the sync disabled, wcout should work independent, so we must set wout's locale to en_US.UTF-8 by
imbue
method, if not do this, the wcout will print content like "??";
- wprintf print "??", that's because we commented out the
std::locale::global(myloc);
, so the locale for stdio is still C locale.
Win10 + vs2022
Output:

My understanding:
- printf and cout print always in order, this is the windows special place, this has been mentioned several times;
- wprintf print empty is equivalent to the "??" in linux;
- so, what's new is the garbled code! i try to uncomment the
std::locale::global(myloc);
code, the print content is ok! so, i think the windows implemention is little special, the wcout may depend on more things that need change locale by global locale setting.
Demo09: print Non-ASCII Characters -- Method C
This demo depends on the windows platform .
#include <cstdio>
#include <iostream>
int main()
{
_setmode(_fileno(stdout), _O_WTEXT); // Unique function to windows
std::wcout << "wcout> " << L"漢字\n";
wprintf(L"wprintf> 漢字\n");
return 0;
}
Win10 + vs2022
Output:

My understanding:
- after _setmode, the globale and wcout locale is still C locale;
- why wcout and wprintf all can print content correctly? i guess maybe the windows implement a mechanism after standard output stream to translate the content by the _setmode specified mode.