Ответы пользователя по тегу Программирование
  • Как передать и проверить много параметров функции?

    @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 комментарий
  • Можно ли одной bitwise операцией (без циклического сдвига) определить степень двойки(номер бита)?

    @monah_tuk
    Для ARM нашёл CLZ (Counting Lead Zeros)
    https://www.scss.tcd.ie/~waldroj/3d1/arm_arm.pdf страница 175.

    не одна bitwise (вычитание добавить нужно), но зато без цикла.

    Теперь не процессоро-специфичное, но компиляторо-специфичное.
    GCC:
    • __builtin_clz() - число лидирующих нулей
    • __builtin_ctz() - число оконченых нулей
    • __builtin_popcount() - число единиц в числе

    https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
    www.go4expert.com/articles/builtin-gcc-functions-b...
    Понятно, что эффективность будет зависеть от того, есть ли реализация на конкретном CPU подобающей команды.

    Вот тут:
    stackoverflow.com/questions/355967/how-to-use-msvc...
    https://msdn.microsoft.com/en-us/library/wfd9z0bb.aspx
    отсылка к реализации MSVC
    Ответ написан
    Комментировать
  • Устройство USB, с чего начать?

    @monah_tuk
    Если будете делать своё USB устройство: изучить спеки, изучить спек HID устройства. На тостере есть советы по использованию либ для AVR для реализации USB стека и HID устройств как пример. Поищите.
    Ответ написан
    Комментировать
  • Почему 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) :)
    Ответ написан
    Комментировать
  • C++ как вызвать метод потомка, не определоного в предке?

    @monah_tuk
    Для начала: не пишите так.

    А так, если классы именно такие, то memory layout у них просто и, грубо, они указывают а одну область памяти. Поэтому поможет простое приведение:
    void foo(A& a) {
      //a.getSome(); //error: class 'A' has no member 'getSome()'
      static_cast<B&>(a).getSome(); // All ok.
    }


    Более того, у вас ещё косяк, такой код:
    B b();
    это не то, что вы подумали, это объявление функции. Всё что выглядит как функция, крякает как функция - функция. Правильно так:
    B b; // дефолтный конструктор не для POD типов вызовется и так

    или так:
    B b = B(); // Накладных расходов не будет. Будет вызван ТОЛЬКО один консутрутор. Компиляторы не совсем дураки.


    Кроме того, надеюсь, класс B описан, на самом деле, как-то так:
    class B : <b>public</b> A {
    <b>public:</b>
      int getSome();
    };

    а не так как у вас.
    Ответ написан
    1 комментарий