Bug 119880 - fwide must be called before and after std::wcout to change wide orientation to allow std::cout works
Summary: fwide must be called before and after std::wcout to change wide orientation t...
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 16.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2025-04-21 03:32 UTC by qingzhe huang
Modified: 2025-05-08 09:19 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description qingzhe huang 2025-04-21 03:32:52 UTC
See following program which requires the first "fwide" so as to allow "std::cout" to work after "std::wcout" calls. This behavior is only with GCC library and MSVC latest can comment the first "fwide" out. This indicates a bug in implementation of GCC stdlib.

#include <cwchar>
#include <iostream>
#include <ostream>
#include <cstdio>
int main() {    
    //std::fwide(stdout, -1); // you cannot comment out this line for GCC!!!
    std::wcout << L"This is a wide line from local wcout." << std::endl;   
    std::fwide(stdout, -1);
    std::cout << "This is a narrow line after wide output." << std::endl;  
    return 0;
}



In GCC family, only "std::wcout" prints while "std::cout" fails to print because stdout is still wide oriented. This can be confirmed by a test "fwide(stdout, 0) > 0" after "std::wcout" prints. 



See www.godbolt.org at https://www.godbolt.org/z/63Gh3xGMh
Comment 1 Jonathan Wakely 2025-04-21 10:13:06 UTC
I think using fwide that way leads to undefined behaviour though. The C standard says:

"Byte input/output functions shall not be applied to a wide-oriented stream and wide character input/output functions shall not be applied to a byte-oriented stream."

So once the stdout stream is byte-oriented, using std::wcout is undefined. And once it's wide-oriented, using std::cout is undefined.

POSIX is clear:

"If the orientation of the stream has already been determined, fwide() shall not change it."
Comment 2 Jonathan Wakely 2025-04-21 10:17:53 UTC
The C standard says that in a footnote for fwide:
"If the orientation of the stream has already been determined, fwide does not change it."

We would need to use freopen to reopen stdout so that it becomes unoriented again, but checking the current orientiation with fwide and then reopening if needed would make every operation on std::cout and std::wcout (and std::cerr, std::wcerr, std::clog and std::wclog) considerably more expensive.
Comment 3 Jonathan Wakely 2025-04-21 10:19:17 UTC
And the C++ standard does not say anything about doing that, implying that the libstdc++ behaviour is expected. Using std::cout makes stdout byte-oriented, and using std::wcout makes it wide-oriented, and then it doesn't change.
Comment 4 Jonathan Wakely 2025-04-21 10:24:24 UTC
It looks like libc++ uses codecvt to convert wide strings to narrow and then always uses byte-oriented I/O on the standard streams.
Comment 5 qingzhe huang 2025-04-22 13:21:45 UTC
I guess you are right about using freopen+fwide to change orientation. Here is also what I learned from this comment (https://stackoverflow.com/a/22950466). 

Actually I am pretty happy with this strange workaround to switch/mix narrow and wide output as long as it works. (https://www.godbolt.org/z/6frxhTovn)
It is only the first call of fwide at very beginning is giving a fishy of bug. Why does MSVC work without this strange call?
Comment 6 Jonathan Wakely 2025-04-22 15:37:03 UTC
Maybe they do the same as libc++ and convert all wide strings to narrow before writing to a byte-oriented stream, or vice versa. Or maybe they don't use stdio for std::cout at all.