Можно ли использовать std :: cout в Android-ndk

В Android-ndk мы могли бы использовать «__android_log_write», «__android_log_print» и т. Д. Для вывода сообщений в окно «LogCat». Как насчет того, чтобы я использовал "std :: cout" для вывода некоторых строк? Например.

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

Куда будут отправлены струны.

Похоже, что в Android нет консольных приложений, и указанные выше строки не могут быть отправлены. Могу ли я перенаправить «stdout» в файл, чтобы отправка строк в «std :: cout» была эквивалентна журналированию сообщений?


person user1129812    schedule 15.01.2012    source источник
comment
подмножество: перенаправить stdout в logcat: stackoverflow.com/questions/10531050/   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 16.02.2016
comment
Возможный дубликат C / C ++ printfs - где он отображается в собственный код Android?   -  person Marcos Vasconcelos    schedule 06.11.2017


Ответы (4)


Согласно документации Android, stdout & stderr выводит в /dev/null. С помощью Android Debug Bridge можно достичь желаемого.

По умолчанию система Android отправляет вывод stdout и stderr (System.out и System.err) в / dev / null. В процессах, которые запускают виртуальную машину Dalvik, вы можете заставить систему записывать копию вывода в файл журнала. В этом случае система записывает сообщения в журнал, используя теги журнала stdout и stderr, оба с приоритетом I. Чтобы направить вывод таким образом, вы останавливаете работающий экземпляр эмулятора / устройства, а затем используете команду оболочки setprop для включения перенаправление вывода. Вот как это сделать:

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

Система сохраняет этот параметр до тех пор, пока вы не завершите работу экземпляра эмулятора / устройства. Чтобы использовать настройку по умолчанию для экземпляра эмулятора / устройства, вы можете добавить запись в /data/local.prop на устройстве.

person parapura rajkumar    schedule 15.01.2012

Вы можете создать класс, производный от 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, либо установить его равным нулю и удалить возврат из rdbuf():

   // avoid a one-time resource leak but don't get output afterwards:
   delete std::cout.rdbuf(0);
person Dietmar Kühl    schedule 15.01.2012
comment
Спасибо за другое решение. Но это требует большего количества кода, попробую позже. - person user1129812; 16.01.2012
comment
Спасибо, работает. Но в нем есть несколько ошибок. Вот исправленная версия: gist.github.com/dzhioev/6127982 - person dzhioev; 01.08.2013
comment
Спасибо! Я изменил код, чтобы он действительно работал, копируя и вставляя, надеюсь, что это может кому-то помочь. (возможно, ожидает экспертной оценки) - person Zsolt Szatmari; 06.10.2014
comment
Ух ты, ты сделал мне жизнь на 100% проще! Хотел бы я дать вам больше, чем положительный голос - person Chris; 09.01.2015
comment
Для меня код отображает журнал только тогда, когда буфер заполнен. - person pvallet; 15.07.2017
comment
@pvallet: Да, это ожидается, если поток явно не очищен, например, с использованием out << std::flush. Отправка символов внешним адресатам обычно довольно дорога и обычно сводится к минимуму. Вы можете отключить буфер в androidbuf, вызывая overflow() для каждого символа (также вводя некоторые дополнительные накладные расходы) и вызывать sync() для определенных символов, например, '\n'. Однако я бы придерживался явной очистки потока. - person Dietmar Kühl; 15.07.2017
comment
Если кто-то хочет очищать буфер после каждого вывода, попробуйте следующее: std :: cout.setf (std :: ios :: unitbuf); - person Zbyl; 28.01.2018

Ответ Дитмара Кюля очень хорош, но он не работает с boost.log из Crystax NDK. Я нашел еще одна идея и немного ее исправили. Вот код:

#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!";
...
person NikitaFeodonit    schedule 02.08.2015

Другой вариант:

#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) Каждый отдельный отпечаток создает объект и разрушает его.

(*** Этот ответ основан на этом ответе)

person y30    schedule 04.08.2016