在Android-ndk中,我们可以使用“__android_log_write”,“_ _ android_log_print”等来将消息输出到“LogCat”窗口。如果我使用“std :: cout”输出一些字符串怎么样? E.g。
std::cout << "some strings" << std::endl;
字符串将在何处发送。
似乎Android没有控制台应用程序,并且可能无法发送上述字符串。我可以将“stdout”重定向到文件,以便将字符串发送到“std :: cout”等同于记录消息吗?
答案 0 :(得分:32)
您可以创建一个派生自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);
答案 1 :(得分:28)
根据Android文档,标准输出&amp; 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添加条目。
答案 2 :(得分:1)
DietmarKü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!";
...
答案 3 :(得分:1)
另一种选择:
#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)立即打印消息。
<强> CONS:强>
(1)你必须改变你的代码(std :: cout - &gt; MY_LOG(X))。
(2)每一个印刷品都会产生一个物体并将其销毁。