2012-01-15 25 views
29

在Android的NDK,我們可以使用「__android_log_write」,「__android_log_print」,...等,以輸出消息「logcat的」窗口「的std ::法院」可用。如果我使用「std :: cout」輸出一些字符串呢?例如。採用的是Android,NDK

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

字符串在哪裏發送。

看來,Android不具備控制檯應用程序和上面的字符串可能無法發送。我可以將「stdout」重定向到一個文件,以便將字符串發送到「std :: cout」相當於記錄消息嗎?

+0

子集:stdout重定向到的logcat:http://stackoverflow.com/questions/10531050/redirect-stdout-to-logcat-in-android-ndk的 – 2016-02-16 13:52:12

+0

可能的複製[C/C++ printfs - 它出現在Android本地代碼中的位置?](https://stackoverflow.com/questions/6426911/cc-printfs-wheres-it-appears-in-a-android-native-code) – 2017-11-06 13:39:06

回答

25

按照Android文檔,標準輸出& 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。

+0

謝謝,它的作品。 – user1129812 2012-01-16 00:03:08

+4

這是否只適用於根植設備? – Ashwini 2012-11-26 08:55:19

29

您可以創建一個派生自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); 
+0

感謝您的解決方案。但它涉及更多的編碼,我會稍後再嘗試。 – user1129812 2012-01-16 00:05:17

+2

謝謝,它的工作。但它有幾個錯誤。這裏是固定版本:https://gist.github.com/dzhioev/6127982 – dzhioev 2013-08-01 02:31:29

+0

謝謝!我修改了代碼,通過複製和粘貼實際工作,希望它可以幫助某人。 (可能正在等待同行評議) – 2014-10-06 13:22:04

1

迪特馬爾·庫爾的答案是非常好的,但它不從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"); 
... 

從升壓所有輸出現在。登錄到std ::法院和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!"; 
... 
2

另一種選擇:

#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 ::法院 - > MY_LOG(X))。

(2)每個單獨的打印產生一個對象並將其銷燬。

(*** This answer base on this answer