Is it possible to remake stdin (or cin) and stdout (or cout) in a library?

Basically, I am coding for an unusual device, with the compiler I've got, cout is working fine but cin does not work, the device doesn't even have a keyboard (another method of inputting text), I need to find a way to basically redirect/remake how stdin reads data and where to read it from. How would I do that from within a library? Would I have to mess with and recompile the standard library somehow?

P.S secondary question. What is the best way to make code automatically run before main when my library is included. I know some libraries make their own main function and instruct the user to use a different one, though that has always seemed a bit hacky to me. I need code to set up the device, I could just put it in a function that must be called before anything else but that also doesn't feel very right to me either.
you can redirect from both windows and unix consoles with a pipe, and the data is as-if-typed. A common use is
foo.exe < file.txt
whatever is in file.txt will be treated as input from keyboard, used to automate test cases for example.


that said you can certainly do any number of other things. What is you want to do, direct the input from the keyboard to the device? Many such device have a serial port, ... you can write a 5 line program that takes keyboard input and shuffles it to the port? Is that useful? (You probably don't even need to write this, its probably something you can get a utility for, there may still be something on the PC that can do it as-is built into the OS).

don't try to run before main. Calling the setup function first is usually correct unless you have a very good reason why it is not useful. This can also be called again in case of a failure state, if needed, so it may be nice to have it functionalized.

Last edited on
The the standard streams stdin, stdout and stderr can be associated with a different file by using the freopen() function:
https://linux.die.net/man/3/freopen

The freopen() function opens the file whose name is the string pointed to by path and associates the stream pointed to by stream with it. The original stream (if it exists) is closed. The mode argument is used just as in the fopen() function. The primary use of the freopen() function is to change the file associated with a standard text stream (stderr, stdin, or stdout).


Also, if you are using GCC or GCC-compatible compiler, have a look at the __attribute__((constructor)) attribute:
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

The constructor attribute causes the function to be called automatically before execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () completes or exit () is called. Functions with these attributes are useful for initializing data that is used implicitly during the execution of the program.
Last edited on
For part 2: Get code to run before main:
myHeader.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef MYHEADER
#define MYHEADER

#include <iostream>

class run
{
        public:
        run()
        {
                std::cout << "On start is running.\n";
        }
};

run onStart;

int test()
{
        std::cout << "Umm. this works too, but somehow it feels less elegant to me...\n";
        return 2;
}
int val = test();

#endif


main.cpp:
1
2
3
4
5
6
7
8
9
10
#include "myHeader.h"
#include "myHeader.h"  // Testing multiple includes, see note at bottom of post
#include <iostream>

using namespace std;

int main()
{
        cout << "This is in main\n";
}



output:
On start is running.
Umm. this works too, but somehow it feels less elegant to me...
This is in main


The only trick is on line 15; have an instance of the object in the header so the constructor is called pretty much first thing at run-time. Technically there's a bunch of code that runs at link-time that sets up C++ environment and the stack and all that, so it's not truly the first code to run, but it's pretty close.

The object's constructor can also be defined in a separate file, I just defined it in the header to make it more readable and skip on posting a third file.

Note: it will only run once despite multiple inclusions since it is wrapped up in #ifndef preprocessor clauses.
Last edited on
Note: it will only run once despite multiple inclusions since it is wrapped up in #ifndef preprocessor clauses.

That doesn't help if the header file is included in separate translation units that are later linked together.

If this issue is sidestepped by including this header file in exactly one translation unit, issues can still arise because the initialization of objects with static storage duration are not ordered across translation units. The potential problem is called the "static initialization order fiasco".
https://en.cppreference.com/w/cpp/language/siof

The multiply-defined symbol issue can be corrected by giving onStart internal linkage:
namespace { run onstart; }
But it creates a secondary issue since each translation unit that includes this header file would construct a separate object.

A reference-counting pattern can be used to ensure that the initialization code only runs once, no matter how many objects are constructed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef MYHEADER
#define MYHEADER
#include <iostream>
class initializer
{ 
  static int& get_refcount() { static int refcount; return refcount;  }

public:
  initializer() 
  { 
    if (get_refcount()++ == 0) std::cout << "initializer::initializer\n"; 
  }
};

namespace { initializer init; }
#endif 

https://coliru.stacked-crooked.com/a/5d3b4f7b551d7b4f

This is fairly safe, provided the programmer doesn't use library functionality before the header is included, or construct the initializer object themselves from multiple threads.
1
2
3
void some_library_function(); 
struct A { A() { some_library_function(); } } a; // wrong
#include <library.h> // defines initializer object 

Finally, doing initialization in this way prevents the user from choosing where and when to run your initialization procedure. In exchange it hides but does not remove the underlying issue.

Consider requiring the user to call init themselves.
Last edited on
It looks like a singleton could also be the answer for the multiple threads issue (using thread locking on instancing for safety, as seen in pseudocode in second link)
https://stackoverflow.com/questions/50609921/singleton-translation-unit-confusion
https://refactoring.guru/design-patterns/singleton

Though comparing a singleton to Mbozzi's reference counting class, they have very similar outcomes. The singleton would remove the chance of multiple initializations from separate threads so it might be slightly more robust.

Edit: Thread locking in Mbozzi's static function get_refcount() should also fix said problem... so I guess it could be just a choice of preference at that point.

I also agree with Mbozzi, just have the user call an init function and a quit function like you see in SDL to save a bunch of headaches. (Note that SDL_Init implements a reference counter using static functions for each subsystem, which is similar to Mbozzi's method.)
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <fstream>
#include <sstream>

namespace utility
{
    struct istream_redirector
    {
        explicit istream_redirector( std::istream& istream, std::streambuf* new_buf ) : stm(istream), old_buf( stm.rdbuf(new_buf) ) {}
        ~istream_redirector() { stm.rdbuf(old_buf) ; }

        istream_redirector( const istream_redirector& ) = delete ;
        istream_redirector& operator= ( const istream_redirector& ) = delete ;

        std::istream& stm ;
        std::streambuf* old_buf ;
    };

    struct redirect_file_to_stdin
    {
        explicit redirect_file_to_stdin( const std::string& path ) : file(path), redirector( std::cin, file.rdbuf() ) {}
        std::ifstream file ;
        istream_redirector redirector ;
    };

    struct redirect_string_to_stdin
    {
        explicit redirect_string_to_stdin( const std::string& text ) : buffer( text, std::ios::in ), redirector( std::cin, std::addressof(buffer) ) {}
        std::stringbuf buffer ;
        istream_redirector redirector ;
    };
}

const utility::redirect_string_to_stdin redirector{ "123 456.78 test!" } ;

int main()
{
    int i = 0 ; // 123
    double d = 0 ; // 456.78
    std::string str ; // test!
    char c = 123 ; // fail, eof
    if( std::cin >> i >> d >> str && i == 123 && d >= 456.7799 && d <= 456.7801 && str == "test!" && !(std::cin>>c) && std::cin.eof() )
        std::cout << "ok\n" ;
}

http://coliru.stacked-crooked.com/a/354a801ffc26cebe
If the initialization procedure might be called from multiple threads there's std::call_once to help. Just make sure that the once_flag is initialized before use.
Topic archived. No new replies allowed.