Different output of UnformattedInputFunction between libc++ and libstdc++

I’m manipulating raw input of keyboard in std c++.

The code working with libstdc++ but libc++.

When UP arrow key stroked,

  • get 1b 5b 41 output if compiled with clang++ -std=c++23 -stdlib=libstdc++ rawkey.cpp. This is correct.
  • get 1b output if compiled with clang++ -std=c++23 -stdlib=libc++ rawkey.cpp

This issue can be reproduced in three deives:

  • HP Z2 G9, i9-13900K, Ubuntu 24.10, clang v19
  • NVidia P3710 Developer Kit, Ubuntu 20.04(DOS 6.0.10), clang v18
  • Arbor FPC-780X, i7-4785T, Fedora 41, clang v19

Here is the source code to re-produce:

#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>

using namespace std;

void get_raw_key()
{
    auto buf = cin.rdbuf();
    vector<int> keys;
    string endline("\r\n");

    auto pump_buf = [&]() {
		cerr << "";	// cin.sync();
					// without this line, debug() has no output
					// if compiled with libstdc++, but libc++ works
					// while libc++ can fetch only one unformatted char
        keys.clear();
        keys.push_back(buf->sbumpc());  // buf->sgetc() buf->sbumpc() getchar()  cin.get()
        while (buf->in_avail() > 0)
            keys.push_back(buf->sbumpc());
    };

    auto dump_key = [&]() {
        stringstream sstr;
        for (const auto num : keys)
            sstr << hex << setw(2) << setfill('0') << num << ' ';
        auto str = sstr.str();
        if (str.size() > 0)
            str.erase(str.end() - 1);
        return str;
    };

    auto debug = [&]() {
        static int count = 0;
        cout << endline << __func__
            << "(" << count << ")"
            << ", in_avail: " << buf->in_avail()
            << ", gcount: " << cin.gcount()
            // << ", bad: " << cin.bad()
            // << ", eof: " << cin.eof()
            // << ", fail: " << cin.fail()
            // << ", good: " << cin.good()
            << ", keys[" << keys.size()
            << "]: " << dump_key()
            << endline;
        count++;
    };

    debug();
    pump_buf();
    dump_key();
    debug();
}

int main(int argc, char *argv[])
{
    system("stty raw");
    cin.sync_with_stdio(false);
    cout << "Please stroke UP arrow key\r\n";
    get_raw_key();
    cout << "\r\n";
    return 0;
}

in_avail() only returns whether there is currently data in the buffer, so there is no guarantee what you actually get with this code. Every output you get here is correct in terms of the C++ standard.

Then how to make sure in_avail() return correct result? Once you pressed Up key in stty raw mode, you’ll get 3 bytes: 1b 5b 41. But in_avail() always return 0, even cin.sync() and waited 2s.

Here is the demo code and output. At least at Step A.4, in_avail() shouldn’t return 0

Please press Up key and wait 2s

A.1 in_avail() return 0
B.1   sbumpc() return ^[[A27
A.2 in_avail() return 0
A.3 in_avail() return 0
B.2   sbumpc() return 91
A.4 in_avail() return 0
B.3   sbumpc() return 65
#include <iostream>
#include <iomanip>
#include <thread>

using namespace std;

// clang++ -std=c++23 -stdlib=libc++ libcxx.cpp 
int main(int argc, char *argv[])
{
	system("stty raw");
	cin.sync_with_stdio(false);
	// cin.tie(nullptr);

	cout << "Please press Up key and wait 2s\r\n";
	cin.sync();

	auto buf = cin.rdbuf();
	cout << "\r\nA.1 in_avail() return " << buf->in_avail();
	cout << "\r\nB.1   sbumpc() return " << buf->sbumpc();
	cout << "\r\nA.2 in_avail() return " << buf->in_avail();
	cin.sync();
	this_thread::sleep_for(chrono::seconds(2));
	cout << "\r\nA.3 in_avail() return " << buf->in_avail();
	cout << "\r\nB.2   sbumpc() return " << buf->sbumpc();
	cout << "\r\nA.4 in_avail() return " << buf->in_avail();
	cout << "\r\nB.3   sbumpc() return " << buf->sbumpc();
	
	cout << "\r\n";
	return 0;
}

There is no “correct result” for in_avail(). That simply returns how many bytes are available in the buffer. If the library doesn’t fill the buffer, it will always be empty. It could also fill the buffer with at most two elements. These are perfectly conforming implementations. If you don’t sync_with_stdio(false), you get the same behaviour with libstdc++.

@philnik One more question, what’s or which library when you said If the library doesn’t fill the buffer, it will always be empty ? Thanks!

That is generally true for all libraries which implement the basic_istream interface, but in this case I meant the standard library you use.