Ответы пользователя по тегу C++
  • Как скомпилировать бинарник ffmpeg?

    @monah_tuk
    env PKG_CONFIG_PATH=/usr/x86_64-w64-mingw32/lib/pkgconfig \
    ../configure \
                 --extra-ldflags="-static-libstdc++ -static-libgcc" \
                 --enable-static \
                 --disable-shared \
                 --enable-nonfree \
                 --enable-libfaac \
                 --enable-libfdk-aac \
                 --enable-cross-compile \
                 --pkg-config=pkg-config \
                 --arch=x86_64 \
                 --target-os=mingw32 \
                 --cross-prefix=x86_64-w64-mingw32-


    а дальше всё зависит от уже собранных библиотек. Вообще, читайте про кросс-компиляцию и т.п.
    Ответ написан
    Комментировать
  • Не могу скомпилировать проект C++ FFMPEG?

    @monah_tuk
    Никогда не собирал FFmpeg под Windows из-под Windows, но попробуй убрать --target-os=XXX вообще - собираешь native, так что он сам должен разобраться.
    Ответ написан
    Комментировать
  • Передать и считать данные с микроконтроллера с использованием libusb?

    @monah_tuk
    Изучите это руководство: habrahabr.ru/post/261955

    А по сути, без дескрипторов USB говорить о чём-то сложно (на Linux: lsusb -v, на Windows: UsbView). Ну и проверить, что у вас действительно используется interrupt трансферинг и на самом устройстве код правильный.

    А так, криминала не вижу: передача на устройство, а значит EP OUT, у вас это EP1, а значит 0x01. Так что, скорее всего, проблема на устройстве. Попробуйте, для начала, control transfering.
    Ответ написан
  • Как перенести QT проект с usblib-win32 на другой пк?

    @monah_tuk
    Не использовать libusb-win32. Использовать оригинальный libusb. Под виндой использовать стандартный драйвер WinUSB. Форсированно его назначить на устройство можно вручную при помощи Zadig или программно libwdi.
    Ответ написан
  • Как определить конец посылки по сокетам?

    @monah_tuk
    Я коллегу выше дополню.

    read/recv возвращает 0 когда соединение закрыто независимо от блокирующего или неблокирующего режима. Если у тебя данных нет в неблокирующем режиме, у тебя вернётся -1 и код ошибки будет EAGAIN или EWOULDBLOCK (WSAEWOULDBLOCK - на win). Проверить код ошибки можно спросив errno (*nix) или WSAGetLastError (win). Эти ошибки - не фатальные, соответственно нужно просто правильно их обработать. В большинстве случаев, правильная обработка - заигнорить :) и повторить запрос. Остальные ошибки обрабатываются согласно логике приложения, но часто - сессия закрывается.

    А ещё, попробуйте использовать Asio/libuv или средства мультиплексирования типа select/poll/epoll/kqueue (или обёртки типа libev/libevent) или асинхронный IO средствами IOCP на Win. Asio и libuv реализуют паттерн проактор и предоставляют лучший асинхронный способ на каждой платформе.
    Ответ написан
    Комментировать
  • Как в с++ узнать имя текущего класса?

    @monah_tuk
    1. Можешь в методе/конструкторе и т.п. это извлечь из __PRETTY_FUNCTION__
    2. Можешь использовать typeid(this)

    Ответ написан
    Комментировать
  • Существует ли хороший стиль программирования на C++11?

    @monah_tuk
    А что мешает всё это и использовать? Или какие-то проблемы есть?
    Ответ написан
    Комментировать
  • Преимущество дружественных функций?

    @monah_tuk
    Когда нужно обеспечить некий доступ к внутрянке, при этом не выставляя её полностью наружу. Функция же может быть определена пользователем. Тем самым мы можем несколько повлиять на логику класса, не изменяя его интерфейсов и не вмешиваясь в бинарный код. Где такое может пригодиться? На вскидку:
    1. Юнит-тестирование
    2. При определении операторов (особенно всяких сложений, вычитаний)
    3. Собственно, изменение, в определённых пределах, поведения класса без наследования (но можно получить палкой, когда внутренняя структура поменяется).

    Но вообще, как это не гуглится? Гуглится!

    1. www.cprogramming.com/tutorial/friends.html последний абзац:
    friend and Encapsulation
    Some people believe that the idea of having friend classes violates the principle of encapsulation because it means that one class can get at the internals of another. One way to think about this, however, is that friend is simply part of a class's overall interface that it shows the world. Just like an elevator repairman has access to a different interface than an elevator rider, some classes or functions require expanded access to the internals of another class. Moreover, using friend allows a class to present a more restrictive interface to the outside world by hiding more details than may be needed by anything but the friends of the class.

    Finally, friends are particularly common in cases of operator overloading because it is often necessary for an overloaded operator to have access to the internals of the classes that are arguments to the operator.


    2. www.cplusplus.com/doc/tutorial/inheritance
    Typical use cases of friend functions are operations that are conducted between two different classes accessing private or protected members of both.


    3. stackoverflow.com/questions/17434/when-should-you-...

    В остальном, если что-то можно сделать без френдов - сделайте без них.
    Ответ написан
    1 комментарий
  • Как уменьшить интервал таймера?

    @monah_tuk
    выбирайте
    #include <chrono>
    #include <thread>
    
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    std::this_thread::sleep_for(std::chrono::microseconds(500));

    и вообще: www.cplusplus.com/reference/chrono/duration

    Если нет C++11 и новее, то есть Boost с точно таким же синтаксисом, только boost:: вместо std::
    Ответ написан
    Комментировать
  • Как C++ обращаться из статического метода к нестатическим текущего класса?

    @monah_tuk
    Коротко: никак.

    Чуть более развёрнуто:
    статический метод класса практически не отличается от простой свободной функции. Отсюда наводка: если showDepFormCreate() будет просто свободной функцией, что будет вкладываться в понятие текущий класс? Так что или передавать инстанс или создавать внутри, зависит от того, что вам нужно. Хотя, чует моё сердце, что-то вы не так делаете.
    Ответ написан
    Комментировать
  • Как передать и проверить много параметров функции?

    @monah_tuk
    Дополню камрада ManWithBear

    Не нужно структуру отдельно переделывать в класс. Это и так класс, только доступ по-умолчанию public. И метод проверки можно не добавлять, а сделать внешним по отношению к структуре. Свободные функции не всегда плохо. Плюсы такого подхода в том, что memory-layout будет предсказуемый, а если в структуре нет non-POD типов то они останутся POD типами.

    Т.е. получится что-то вроде такого:
    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    struct Point
    {
      int x;
      int y;
    };
    inline bool is_valid(const Point& p)
    {
      bool result = true;
      // some checks
      return result;
    }
    
    struct Rect : Point
    {
      int width;
      int height;
    };
    inline bool is_valid(const Rect& r)
    {
      bool result = is_valid(static_cast<const Point&>(r)) && r.width > 0 && r.height > 0;
      return result;
    }
    
    int main() {
    	// теряется возможность делать так:
    	//Rect r = {0, 1, 2, 3};
    	Rect r{};
    	r.x = 0;
    	r.y = 1;
    	r.width  = 10;
    	r.height = 11;
    	
    	auto check = is_valid(r);
    	
    	cout << " x=" << r.x
    	     << " y=" << r.y
    	     << " w=" << r.width
    	     << " h=" << r.height
    	     << " valid=" << check
    	     << endl;
    	
    	cout << sizeof(Rect) << "/" << sizeof(int)*4 << endl;
    	
    	uint8_t *ptr = reinterpret_cast<uint8_t*>(&r);
    	auto beg = ptr;
    	auto end = ptr + sizeof(Rect);
    	for (auto it = beg; it != end; ++it) {
    		cout << hex << setfill('0') << setw(2) << (int)*it << " ";
    	}
    	cout << endl;
    	
    	return 0;
    }


    Можно функцию проверки сделать и методом класса/структуры и, при этом, не виртуальной. Тогда проверка будет вызываться только в соответствии с типом. Тогда можно обойтись без static_cast, получится что-то вроде:
    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    struct Point
    {
      int x;
      int y;
      
      bool is_valid() const
      {
      	bool result = true;
      	// some checks
      	return result;
      }
    };
    
    struct Rect : Point
    {
      int width;
      int height;
    
      bool is_valid() const
      {
      	bool result = Point::is_valid() && width > 0 && height > 0;
      	return result;
      }
    };
    
    void pass_point(const Point &p)
    {
    	cout << "point is valid: " << p.is_valid() << endl;
    }
    
    int main() {
    	// теряется возможность делать так:
    	//Rect r = {0, 1, 2, 3};
    	Rect r{};
    	r.x = 0;
    	r.y = 1;
    	r.width  = 0; // make invalid
    	r.height = 11;
    	
    	auto check = r.is_valid();
    	
    	cout << " x=" << r.x
    	     << " y=" << r.y
    	     << " w=" << r.width
    	     << " h=" << r.height
    	     << " valid=" << check
    	     << endl;
        
        // но следующий вызов скажет что точка валидна:
        // вызов валиден, т.к. Rect отнаследован от Point
        pass_point(r);
    	
    	cout << sizeof(Rect) << "/" << sizeof(int)*4 << endl;
    	
    	uint8_t *ptr = reinterpret_cast<uint8_t*>(&r);
    	auto beg = ptr;
    	auto end = ptr + sizeof(Rect);
    	for (auto it = beg; it != end; ++it) {
    		cout << hex << setfill('0') << setw(2) << (int)*it << " ";
    	}
    	cout << endl;
    	
    	return 0;
    }


    Сложности могут возникнуть, когда появятся ромбические связи и потребуется виртуальное наследование.
    Ответ написан
    1 комментарий
  • Как обращаться к форме из стороннего юнита?

    @monah_tuk
    У вас, ещё и Header guard, небось, есть? Или #pragma once?

    Изучите как работает препроцессор и что они делает, когда встречает директиву #include.

    По вашей проблеме:
    Func.cpp подключает Func.h (определяется охранник FUNC_H /какой точно у вас - я не знаю/, теперь файл повторно не включится), тот, в свою очередь, подключает Main.h (MAIN_H), Main.h подключает Func.h, но охранник уже есть, поэтому игнорируется. Из текста ошибки следует, что не смог подключиться Main.h, т.к. был определён охранник MAIN_H, попробую возомнить себя телепатом, но, скорее всего, в Func.cpp у вас сначала инклудится Main.h, а потом Func.h, что и приводит к такому поведению.

    Собственно, вам уже должно стать понятно, что без листингов этих файлов делать заключение очень проблемно. Ровно как и оказать посильную помощь.

    А вообще, золотое правило: избегайте cross-reference заголовочных файлов. Подключайте нужные только в единицы трансляции. Используйте forward-declaration где нужно. Скрывайте детали реализации через PIMPL (гугл в помощь).
    Ответ написан
    3 комментария
  • Из-за чего может быть ошибка?

    @monah_tuk
    Как минимум, вы один и тот же стрим ввода передаёте всем тредам. Тут имеет место быть не только гонка, но и вообще каша с доступом. Затем тред на продолжении ВСЕЙ своей работы блокирует мутекс. Ваш вариант с тем же успехом мог бы работать в один поток, т.к. пока поток не окончит чтение, другие будут ждать на мутексе. Блокируйте только на доступе к вектору.

    Как вариант такой код:
    #include <iostream>
    #include <string>
    #include <fstream>
    #include <sstream>
    #include <vector>
    #include <deque>
    #include <map>
    #include <thread>
    #include <mutex>
    
    std::mutex lock;
    
    void pipeline(const std::string&, std::vector<std::string>&);
    
    
    std::string files[4] =
            {
                    "file1.txt",
                    "file2.txt",
                    "file3.txt",
                    "file4.txt"
            };
    
    int main()
    {
        std::string string;
        std::vector<std::string> str;
        std::map<std::string, std::size_t> freq;
        std::deque<std::thread> pool;
        std::ofstream out("out.txt");
    
        for (std::size_t i = 0; i < 3; i++)
        {
            pool.push_back(std::thread(pipeline, std::ref(files[i]), std::ref(str)));
        }
    
        while (pool.size())
        {
            pool.front().join();
            pool.pop_front();
        }
    
        std::cout << str.size();
    
        return 0;
    }
    
    void pipeline(const std::string &infile, std::vector<std::string> &str)
    {
        std::ifstream in(infile.c_str());
    
        while (!in.eof())
        {
            std::string temp;
    
            std::getline(in, temp);
    
            {
                std::unique_lock<std::mutex> guard(lock);
                str.push_back(temp);
            }
        }
    }


    Изменения:
    - стрим создаётся в потоке, потоку передаётся имя файла
    - блокировка доступа только на модификации вектора
    - использование охранного класса для блокирования и освобождения верктора.
    - close на стриме можно в данном случае не делать - он закроется по выходу из области видимости
    Ответ написан
    1 комментарий
  • Как при помощи C++ узнать информацию о системе?

    @monah_tuk
    А на Linux посмотри исходники lshw (либо парсируй её вывод) и, в дополнение:
    - lspci
    - lsusb
    - /proc/cpuinfo
    Ответ написан
    Комментировать
  • Почему wstring::c_str() не выводит русскую часть текста?

    @monah_tuk
    imbue() применяет локаль для оперций ввода-вывода, типа: как выводить разделитель дроби: точку или запятую. Тебе в начале, до операций ввода-вывода, нужно поставить:
    std::locale system("");
    std::locale::global(system);


    Вот более полный пример, в котором видно отличия:
    #include <iostream>
    #include <locale>
    
    using namespace std;
    
    int main()
    {
        std::locale system("");
        std::locale::global(system);
    
        wstring str = L"hello, world. привет, МКС";
        wcout << str << endl;
        wcout << str.c_str() << endl;
    
        wcout << 3.14 << endl;
        // А теперь будет десятичный разделитель согласно локали выводится
        wcout.imbue(system);
        wcout << 3.14 << endl;
    
        return 0;
    }


    Вывод такой:
    hello, world. привет, МКС
    hello, world. привет, МКС
    3.14
    3,14


    UPD: еще, неплохо, при помощи setlocale() установить Си-локаль, которую библиотека Си использует. Ага, они разные, и ставятся независимо (https://stdcxx.apache.org/doc/stdlibug/24-3.html) :)
    Ответ написан
    Комментировать
  • На чем лучше программировать визуальные приложения?

    @monah_tuk
    Судя по вопросу, у вас порог не того уровня, что бы заниматься C++. Отгребёте больше проблем, чем получите пользы.

    Тут говорили уже про Qt, я предлагаю вам использовать связку Qt + Python. По крайней мере с выделениями памяти вы себя малость обезопасите. Ссылки по теме:
    Python + PyQt + Qt Designer. Что дальше?
    www.youtube.com/watch?v=3SS0CeEs4ro - показан пример работы с IDE PyCharm от Jet Brains. Не смотрите, что под Ubuntu, под виндой точно так же.
    https://ru.wikipedia.org/wiki/PyQt - вообще информация по проекту
    Ответ написан
  • Как обнулить std::cin и заставить его ждать ввода?

    @monah_tuk
    Входная программа завершила писать и ваша получила EOF. Всё, баста карапузики. Проверяйте статус ввода и завершайтесь - больше вы данных не получите, никогда и ни при каких условиях.

    Не верите? Отправьте на stdin не одну строку, а файл: выведется правильно файл, а потом посыпят пустые строки или последний токен - зависит от реализации.

    Обратите внимание на слово токен - у вас разделение по пробелу будет. Что бы читать строку, используйте std::getline().

    За флагами:
    www.cplusplus.com/reference/ios/ios/eof
    www.cplusplus.com/reference/ios/ios/fail
    www.cplusplus.com/reference/ios/ios/bad

    Ну а ваш код, по сути, должен стать таким:
    while (true) {
            std::getline(std::cin, line);
            if (!std::cin)
                break;
            std::cout << "out: " + line << std::endl;
        }


    обратите внимание, что если вы сделаете так:
    while (std::cin) {
            std::getline(std::cin, line);
            std::cout << "out: " + line << std::endl;
        }


    то вроде короче, и вроде работает, но будете постоянно выводить одну лишнюю строку (пустую или нет - от реализации), так что поверить статус стоит перед процессингом того, что получили.
    Ответ написан
    6 комментариев
  • Как подключить заголовочный файл частично?

    @monah_tuk
    Не вижу никаких проблем: не подключайте его совсем. А в начале своего модуля просто объявите прототип функции:
    extern "C" int printf(const char *format, ...);

    и потом используй в своё удовольствие: компилятору вы обещание дали, а линковщик разберётся. Главное - extern "C", что говорит использовать манглинг имён в стиле C, а не C++. Естественно, если используется что-то, что не объявлено в stdio.h, но косвенно инклудится, то нужно подключать уже.
    Ответ написан
    2 комментария
  • Какие самые печальные/курьезные по последствиям баги в вашей практике (или о которых знаете)?

    @monah_tuk
    Не у меня, но в моей практике: htrd.su/wiki/zhurnal/2013/09/18/zabavnyj_bag

    Ещё:
    Останавливался шедулер ThreadX и, соответственно, продолжал выполняться только один тред, либо, когда доходило до кооперативного передачи управления. Проблема: отображённый в память регистр регистр управления таймером после записи не сразу возвращает, при чтении, новое значение. Плюс один регистр использовался для двух таймеров, соответственно, что настроить второй, нужно вычитать значение, подправить его и записать обратно, что бы параметры первого не перезаписать. Планировщик на время решедулинга гасил свой таймер, а потом активировал. Но случалось так, что после активирования не сразу обновлялся, а к этому моменту наш код успевал вычитать регистр, с погашенным значением, активировал свой таймер и записывал. В результате таймер планировщика оказывался выключенным. Гонки в прямом смысле не было: доступ планировщика из прерывания, а наш код запускается непосредственно им уже после активации. Ситуация усугублялась тем, что система могла некоторое время работать за счёт кооперативной многозадачности (например, при блокировке на мутексе, вызывается дополнительно код, проверяющий, а не готов ли какой тред, и запускает его, участие планировщика тут не нужно, аналогично при вызове других системных процедур, типа sleep(), ожидание треда и т.п.), но гасло часто в непредсказуемый момент. Это embedded ;-)
    Ответ написан
    2 комментария