Is “std::cout” usable in Android-ndk

前端 未结 4 1482
-上瘾入骨i
-上瘾入骨i 2020-12-02 18:31

In Android-ndk, we could use \"__android_log_write\", \"__android_log_print\", ... etc to output messages to the \"LogCat\" window. How about if I use \"std::cout\" to outpu

相关标签:
4条回答
  • 2020-12-02 18:46

    You can create a class derived from std::streambuf which uses the Android specific functions to send the produced sequence of characters. I don't know where the default implementation of std::cout sends characters on Android, however. Basically, this would look something like this:

    class androidbuf : public std::streambuf {
    public:
        enum { bufsize = 128 }; // ... or some other suitable buffer size
        androidbuf() { this->setp(buffer, buffer + bufsize - 1); }
    
    private:
        int overflow(int c)
        {
            if (c == traits_type::eof()) {
                *this->pptr() = traits_type::to_char_type(c);
                this->sbumpc();
            }
            return this->sync()? traits_type::eof(): traits_type::not_eof(c);
        }
    
        int sync()
        {
            int rc = 0;
            if (this->pbase() != this->pptr()) {
                char writebuf[bufsize+1];
                memcpy(writebuf, this->pbase(), this->pptr() - this->pbase());
                writebuf[this->pptr() - this->pbase()] = '\0';
    
                rc = __android_log_write(ANDROID_LOG_INFO, "std", writebuf) > 0;
                this->setp(buffer, buffer + bufsize - 1);
            }
            return rc;
        }
    
        char buffer[bufsize];
    };
    

    To actually set up std::cout to write to this stream buffer, you would do something like this in your main() function:

    int main() {
        std::cout.rdbuf(new androidbuf);
        ...
    }
    

    This create a memory leak for the one androidbuf stream which is, however, somewhat intentional: the stream may be written to after main() is exited and it is flushed when when std::cout gets destroyed. If you don't want this, you could either restore std::cout's original stream buffer or set it to null and delete the return from rdbuf():

       // avoid a one-time resource leak but don't get output afterwards:
       delete std::cout.rdbuf(0);
    
    0 讨论(0)
  • 2020-12-02 18:52

    The answer of Dietmar Kühl is very good, but it do not work with boost.log from Crystax NDK. I found another idea and have corrected it a little. Here is the code:

    #include <iostream>
    #include <unistd.h>
    #include <pthread.h>
    #include <android/log.h>
    
    static int pfd[2];
    static pthread_t thr;
    static const char *tag = "myapp";
    
    static void *thread_func(void*)
    {
        ssize_t rdsz;
        char buf[128];
        while((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) {
            if(buf[rdsz - 1] == '\n') --rdsz;
            buf[rdsz] = 0;  /* add null-terminator */
            __android_log_write(ANDROID_LOG_DEBUG, tag, buf);
        }
        return 0;
    }
    
    int start_logger(const char *app_name)
    {
        tag = app_name;
    
        /* make stdout line-buffered and stderr unbuffered */
        setvbuf(stdout, 0, _IOLBF, 0);
        setvbuf(stderr, 0, _IONBF, 0);
    
        /* create the pipe and redirect stdout and stderr */
        pipe(pfd);
        dup2(pfd[1], 1);
        dup2(pfd[1], 2);
    
        /* spawn the logging thread */
        if(pthread_create(&thr, 0, thread_func, 0) == -1)
            return -1;
        pthread_detach(thr);
        return 0;
    }
    

    And its use:

    ...
    start_logger("MyApp");
    ...
    

    Now all output from boost.log to std::cout and std::cerr will be in logcat:

    #include <boost/log/utility/setup/console.hpp>
    #include <boost/log/utility/setup/common_attributes.hpp>
    #include <boost/log/sources/record_ostream.hpp>
    #include <boost/log/sources/logger.hpp>
    
    ...
    boost::log::add_console_log(std::cout);
    boost::log::add_common_attributes();
    
    boost::log::sources::logger_mt lg;
    BOOST_LOG(lg) << "Hello, World!";
    ...
    
    0 讨论(0)
  • 2020-12-02 18:53

    According to the Android documentation, stdout & stderr output to /dev/null. You can use the Android Debug Bridge to achieve what you want.

    By default, the Android system sends stdout and stderr (System.out and System.err) output to /dev/null. In processes that run the Dalvik VM, you can have the system write a copy of the output to the log file. In this case, the system writes the messages to the log using the log tags stdout and stderr, both with priority I. To route the output in this way, you stop a running emulator/device instance and then use the shell command setprop to enable the redirection of output. Here's how you do it:

    $ adb shell stop
    $ adb shell setprop log.redirect-stdio true
    $ adb shell start
    

    The system retains this setting until you terminate the emulator/device instance. To use the setting as a default on the emulator/device instance, you can add an entry to /data/local.prop on the device.

    0 讨论(0)
  • 2020-12-02 19:01

    Another option:

    #include <sstream>
    
    class MyStream
    {
    private:
       std::stringstream m_ss;
       int m_logLevel;
    public:
    
       MyStream(int Xi_logLevel)
       {
          m_logLevel = Xi_logLevel;
       };
       ~MyStream()
       {
          __android_log_print(m_logLevel,LOG_TAG,"%s", m_ss.str().c_str());
       }
    
       template<typename T> MyStream& operator<<(T const& Xi_val)
       {
          m_ss << Xi_val;
          return *this;
       }
    };
    
    #define MY_LOG(LOG_LEVEL) MyStream(ANDROID_LOG_##LOG_LEVEL) << __FUNCTION__ << ":" << __LINE__ << " : "
    

    PROS:

    (1) The messages are printed immediately.

    CONS:

    (1) You must to change your code (std::cout -> MY_LOG(X)).

    (2) Each a single print produces an object and destroys it.

    (*** This answer base on this answer)

    0 讨论(0)
提交回复
热议问题