c++ “std::cout”在Android-ndk中可用吗

qcbq4gxm  于 2023-05-19  发布在  Android
关注(0)|答案(5)|浏览(131)

在Android-ndk中,我们可以使用“__android_log_write”,“__android_log_print”,...等将消息输出到“LogCat”窗口。如果我使用“std::cout”来输出一些字符串呢?例如:

std::cout << "some strings" << std::endl;

字符串将被发送到哪里。
Android似乎没有控制台应用程序,上述字符串可能无法发送。我可以将“stdout”重定向到一个文件,这样发送字符串到“std::cout”就相当于记录消息吗?

yyhrrdl8

yyhrrdl81#

您可以创建一个从std::streambuf派生的类,它使用Android特定的函数来发送生成的字符序列。但是,我不知道std::cout的默认实现在Android上发送字符的位置。基本上,它看起来像这样:

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];
};

要真正设置std::cout来写入这个流缓冲区,您可以在main()函数中执行以下操作:

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

这为一个androidbuf流创建了内存泄漏,然而,这在某种程度上是故意的:可以在退出main()之后写入流,并且当std::cout被破坏时刷新该流。如果你不想这样,你可以恢复std::cout的原始流缓冲区,或者将其设置为null并删除rdbuf()的返回:

// avoid a one-time resource leak but don't get output afterwards:
   delete std::cout.rdbuf(0);
9rygscc1

9rygscc12#

根据Android文档,stdout & stderr输出到/dev/null。您可以使用**Android Debug Bridge**来实现您想要的。
默认情况下,Android系统将stdout和stderr(System.out和System.err)输出发送到/dev/null。在运行Dalvik VM的进程中,您可以让系统将输出的副本写入日志文件。在本例中,系统使用日志标记stdout和stderr(两者的优先级都为I)将消息写入日志。要以这种方式路由输出,请停止正在运行的模拟器/设备示例,然后使用shell命令setprop启用输出重定向。你应该这么做:

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

系统将保留此设置,直到您终止模拟器/设备示例。要将该设置用作模拟器/设备示例上的默认设置,可以在设备上的/data/local.prop中添加一个条目。

zlhcx6iw

zlhcx6iw3#

另一个选择:

#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__ << " : "

优点:

(1)消息立即打印。

缺点:

(1)你必须修改你的代码(std::cout -> MY_LOG(X))。
(2)每一个单一的打印产生一个对象和破坏它。
(***This answer base on this answer

ojsjcaue

ojsjcaue4#

Dietmar Kühl的答案非常好,但它不适用于Crystax NDK的boost.log。我找到了another idea,并进行了一些更正。代码如下:

#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;
}

其用途:

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

现在boost.log到std::cout和std::cerr的所有输出都将在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!";
...
3pmvbmvn

3pmvbmvn5#

在android studio logcat中打印日志的简单方法。
步骤1:将以下行添加到公共头文件中。

#include <android/log.h>
    
#define LOGV(TAG, ...) __android_log_print(ANDROID_LOG_VERBOSE, TAG,__VA_ARGS__)
#define LOGD(TAG, ...) __android_log_print(ANDROID_LOG_DEBUG  , TAG,__VA_ARGS__)
#define LOGI(TAG, ...) __android_log_print(ANDROID_LOG_INFO   , TAG,__VA_ARGS__)
#define LOGW(TAG, ...) __android_log_print(ANDROID_LOG_WARN   , TAG,__VA_ARGS__)
#define LOGE(TAG, ...) __android_log_print(ANDROID_LOG_ERROR  , TAG,__VA_ARGS__)

第二步:现在打电话

LOGV("MYTAGNAME", "Hello!!");
LOGD("MYTAGNAME", "Hello!!");
LOGI("MYTAGNAME", "Hello!!");
LOGW("MYTAGNAME", "Hello!!");
LOGE("MYTAGNAME", "Hello!!");

第三步:你可以在logcat中看到如下的日志。

相关问题