2012-01-15 31 views
29

Trong Android-ndk, chúng tôi có thể sử dụng "__android_log_write", "__android_log_print", ... vv để xuất thông báo tới cửa sổ "LogCat". Làm thế nào về nếu tôi sử dụng "std :: cout" để sản xuất một số dây? Ví dụ.Là "std :: cout" có thể sử dụng trong Android-ndk

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

Chuỗi sẽ được gửi đến đâu.

Dường như Android không có Ứng dụng giao diện điều khiển và các chuỗi ở trên có thể không được gửi. Tôi có thể chuyển hướng "stdout" vào một tệp để gửi chuỗi tới "std :: cout" tương đương với thông điệp ghi nhật ký không?

+0

tập hợp con: chuyển hướng stdout để logcat: http://stackoverflow.com/questions/10531050/redirect-stdout-to-logcat-in-android-ndk –

+0

trùng lặp có thể có của [C/C++ printfs - Nó xuất hiện ở đâu trong mã gốc của Android?] (Https://stackoverflow.com/questions/6426911/cc-printfs-wheres-it-appears-in-a-android-native-code) –

Trả lời

25

Theo tài liệu Android, stdout & stderr xuất thành /dev/null. Bạn có thể sử dụng Android Debug Bridge để đạt được những gì bạn muốn.

Theo mặc định, hệ thống Android sẽ gửi đầu ra stdout và stderr (System.out và System.err) đến/dev/null. Trong các quá trình chạy VM Dalvik, bạn có thể có hệ thống ghi một bản sao của đầu ra vào tệp nhật ký. Trong trường hợp này, hệ thống ghi các thông điệp vào nhật ký bằng cách sử dụng các thẻ log stdout và stderr, cả hai với mức ưu tiên I. Để định tuyến đầu ra theo cách này, bạn dừng một trình mô phỏng chạy/thiết bị chạy và sau đó sử dụng lệnh shell setprop cho phép chuyển hướng đầu ra. Đây là cách bạn làm điều đó:

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

Hệ thống giữ lại thiết lập này cho đến khi bạn chấm dứt dụ giả lập/thiết bị. Để sử dụng cài đặt làm mặc định trên phiên bản trình mô phỏng/thiết bị, bạn có thể thêm mục nhập vào /data/local.prop trên thiết bị.

+0

Cảm ơn, nó hoạt động. – user1129812

+4

Tính năng này chỉ hoạt động trên các thiết bị được root? – Ashwini

29

Bạn có thể tạo lớp bắt nguồn từ std::streambuf sử dụng các chức năng cụ thể của Android để gửi chuỗi ký tự được tạo ra. Tôi không biết nơi triển khai mặc định của std::cout gửi các ký tự trên Android, tuy nhiên. Về cơ bản, điều này sẽ giống như thế này:

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

Để thực sự thành lập std::cout để viết thư cho bộ đệm dòng này, bạn sẽ làm điều gì đó như thế này trong chức năng main() của bạn:

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

này tạo ra một ký ức rò rỉ cho một luồng androidbuf, tuy nhiên, có chủ ý: luồng có thể được ghi sau main() bị thoát và nó bị xóa khi khi std::cout bị hủy. Nếu bạn không muốn điều này, bạn có thể khôi phục một trong hai dòng đệm ban đầu std::cout 's hoặc thiết lập nó để null và xóa sự trở lại từ rdbuf():

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

Cảm ơn một giải pháp khác. Nhưng nó liên quan đến mã hóa nhiều hơn, tôi sẽ thử nó sau này. – user1129812

+2

Cảm ơn bạn, nó hoạt động. Nhưng nó có một số sai lầm. Đây là phiên bản cố định: https://gist.github.com/dzhioev/6127982 – dzhioev

+0

Cảm ơn! Tôi đã sửa đổi mã để thực sự hoạt động bằng cách sao chép và dán, hy vọng nó có thể giúp ai đó. (có thể đang chờ xem xét ngang hàng) –

1

Câu trả lời của Dietmar Kuhl là rất tốt, nhưng nó không làm việc với boost.log từ Crystax NDK. Tôi tìm thấy another idea và đã sửa lại một chút. Đây là mã:

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

Và việc sử dụng nó:

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

Bây giờ tất cả sản lượng từ tăng.đăng nhập để std :: cout và std :: cerr sẽ được trong 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

Một tùy chọn khác:

#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) Các thông điệp được in ngay lập tức.

Nhược điểm:

(1) Bạn phải thay đổi mã của bạn (std :: cout -> MY_LOG (X)).

(2) Mỗi ​​bản in đơn tạo ra một đối tượng và phá hủy nó.

(*** This answer base on this answer)

Các vấn đề liên quan