Задать вопрос
  • При компиляции VC++, Opencv 3.2 проекта не работает exe на другой системе, требует opencv_world330.dll что делать?

    @Mercury13
    Программист на «си с крестами» и не только
    Краш, вероятно, связан с другой вещью. Компилятор-то новенький, и на ту машину не успели подвезти его среду исполнения. Выясни, какие файлы нужны: MSVCR140.DLL, MSVCP140.DLL или MFC140U.DLL.
    (при условии, что сам OpenCV также скомпилирован C++2017; если нет — также нужны и файлы другого компилятора.)

    Если так и не удастся отыскать — найди программу Dependency Walker и точно найди, чего ей не хватает.
    Ответ написан
    6 комментариев
  • Сортировка по нескольким полям в одном компараторе?

    @Mercury13
    Программист на «си с крестами» и не только
    Не понял. Если по одному, при равенстве — по другому, если всё ещё равны — по третьему, то примерно так.
    public int CompareTo(Book book)
        {
          if (book != null)
          {
            int r = name.CompareTo(book.name);
            if (r != 0)
              return r;
            r = author.CompareTo(book.author);
            if (r != 0)
              return r;
            return Math.sign(releaseDate - book.releaseDate);
          }
          else
          {
            throw new Exception("Невозможно сравнить два объекта");
          }
        }


    Если же вы хотите, чтобы, в зависимости от каких-то настроек, сортировало то по названию, то по автору, сделайте коллекцию разнотипных объектов.
    const int NAME = 0, AUTHOR = 1, COUNT = 2;
    
    class ByName : Comparer<Book> {}
    class ByAuthor : IComparer<Book> {}
    
    Comparer<Book> comparers[COUNT] = {  new ByName(), new ByAuthor() };

    C# знаю плохо, возможны синтаксические ошибки.

    Третий вариант — для полей одинаковых типов сделать унифицированный доступ.
    const int S_NAME = 0, S_AUTHOR = 1, S_COUNT = 2;
    const int I_DATE = 0;
    
    public class Book
    {
        string stringFields[S_COUNT];
        int intFields[I_COUNT];
    
        public string name {
            get { return stringFields[S_NAME; ] }
            set { stringFields[S_NAME] = value; }
        }
    }
    
    class StringComparer : IComparer<Book> {
       int code;
       StringComparer(int aCode) { code = aCode; }
       int Compare(Book a, Book b) { return a.stringFields[code].compareTo(b.stringFields[code]); }
    }
    
    const int ALL_NAME = 0, ALL_AUTHOR = 1, ALL_DATE=2, ALL_COUNT = 3;
    
    Comparer<Book> comparers[ALL_COUNT] = {  
       new StringComparer(S_NAME), new StringComparer(S_AUTHOR), new IntComparer(I_DATE) };
    Ответ написан
    2 комментария
  • Возможен ли в XML атрибут с пространством имён ранее XMLNS?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Опять приходится отвечать самому. Возможен.
    www.oracle.com/technetwork/articles/srivastava-nam...
    <?xml version="1.0"?>
    <Book isbn="1234"
          pfx:cover="hard"
          xmlns="http://www.library.com"
          xmlns:pfx="http://www.library.com">
      <Title>Sherlock Holmes</Title>
      <Author>Arthur Conan Doyle</Author>
    </Book>
    Ответ написан
    Комментировать
  • Как правильно из zip архива считать текстовый файл с помощью PHYSFS?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужно закрыть Си-строку.
    int length = PHYSFS_fileLength(myfile)
    myBuf = new char[length + 1];
    int length_read = PHYSFS_read(myfile, myBuf, 1, length);
    myBuf[length_read] = 0;
    Ответ написан
    Комментировать
  • Как превратить то что вернет WM_CHAR в юникод?

    @Mercury13
    Программист на «си с крестами» и не только
    Recardo_Recoly,
    Понятно.
    1. Лучше использовать WM_UNICHAR, он работает и с кодами более 65535. Поддерживается как минимум WinXP.
    2. Как превратить кодовую позицию в UTF-8, есть много вариантов. Сейчас найду свой.

    enum {
        SURROGATE_MIN = 0xD800,
        SURROGATE_MAX = 0xDFFF,
        SURROGATE_LO_MIN = SURROGATE_MIN,
        SURROGATE_HI_MIN = 0xDC00,
        SURROGATE_LO_MAX = SURROGATE_HI_MIN - 1,
        SURROGATE_HI_MAX = SURROGATE_MAX,
        UNICODE_MAX = 0x10FFFF,
        U8_1BYTE_MAX = 0x7F,
        U8_2BYTE_MIN = 0x80,
        U8_2BYTE_MAX = 0x7FF,
        U8_3BYTE_MIN = 0x800,
        U8_3BYTE_MAX = 0xFFFF,
        U8_4BYTE_MIN = 0x10000,
        U8_4BYTE_MAX = UNICODE_MAX,
        U16_1WORD_MAX = 0xFFFF,
        U16_2WORD_MIN = 0x10000,
        U16_2WORD_MAX = UNICODE_MAX,
    };
    
    void str::putCpNe (char*& p, unsigned long aCp)
    {
        if (aCp <= U8_2BYTE_MAX) {  // 1 or 2 bytes, the most frequent case
            if (aCp <= U8_1BYTE_MAX) {  // 1 byte
                *(p++) = static_cast<char>(aCp);
            } else { // 2 bytes
                *(p++) = static_cast<char>((aCp >> 6)   | 0xC0);
                *(p++) = static_cast<char>((aCp & 0x3F) | 0x80);
            }
        } else {  // 3 or 4 bytes
            if (aCp <= U8_3BYTE_MAX) {  // 3 bytes
                *(p++) = static_cast<char>( (aCp >> 12)        | 0xE0);
                *(p++) = static_cast<char>(((aCp >> 6) & 0x3F) | 0x80);
                *(p++) = static_cast<char>( (aCp       & 0x3F) | 0x80);
            } else {    // 4 bytes
                *(p++) = static_cast<char>(((aCp >> 18) & 0x07) | 0xF0);
                *(p++) = static_cast<char>(((aCp >> 12) & 0x3F) | 0x80);
                *(p++) = static_cast<char>(((aCp >> 6)  & 0x3F) | 0x80);
                *(p++) = static_cast<char>( (aCp        & 0x3F) | 0x80);
            }
        }
    }
    
    void str::appendCp(std::string & s, unsigned long aCp)
    {
        char c[5];
        char* end = c;
        putCpNe(end, aCp);
        s.append(c, end);
    }

    Слово Cp у меня означает code point, кодовая позиция Юникода. Ne — no error-checking, без проверки кодовых позиций на корректность.

    В Си++ есть и штатные функции преобразования кодовых позиций Юникода в UTF-8 и UTF-16. Но страшны, как чёрт, и половина из них в C++17 deprecated :(

    И последнее, что я хочу сказать.
    Вы путаете две вещи: Юникод и его кодовые позиции, и форматы записи юникодных строк UTF-8 и UTF-16. Соотношение «один символ Юникода — один char» только в UTF-32!
    Ответ написан
    33 комментария
  • Как в С++ из INT сделать string16?

    @Mercury13
    Программист на «си с крестами» и не только
    UTF-8 — это многобайтовая кодировка и у неё нет кодов. Так что считаем, что имеем дело с кодами Юникода.
    Это только кусок моей мини-библиотеки, так что…

    Шаблон использовался, чтобы автоматически специализировать под нужную длину wchar_t, реально есть версии под 1 и 2.
    namespace str{
    
    enum {
        SURROGATE_MIN = 0xD800,
        SURROGATE_MAX = 0xDFFF,
        SURROGATE_LO_MIN = SURROGATE_MIN,
        SURROGATE_HI_MIN = 0xDC00,
        SURROGATE_LO_MAX = SURROGATE_HI_MIN - 1,
        SURROGATE_HI_MAX = SURROGATE_MAX,
        UNICODE_MAX = 0x10FFFF,
        U8_1BYTE_MAX = 0x7F,
        U8_2BYTE_MIN = 0x80,
        U8_2BYTE_MAX = 0x7FF,
        U8_3BYTE_MIN = 0x800,
        U8_3BYTE_MAX = 0xFFFF,
        U8_4BYTE_MIN = 0x10000,
        U8_4BYTE_MAX = UNICODE_MAX,
        U16_1WORD_MAX = 0xFFFF,
        U16_2WORD_MIN = 0x10000,
        U16_2WORD_MAX = UNICODE_MAX,
    };
    
    template <int Len>
    void putCpNeT (wchar_t*& p, unsigned long aCp);
    
    ///  Puts a code-point in wchar_t encoding, w/o error-checking
    ///  @param [in,out]  p     position to put to
    ///  @param [in]      aCp   code-point, surely valid
    inline void putCpNe (wchar_t*& p, unsigned long aCp)
        { putCpNeT<sizeof(wchar_t)>(p, aCp); }
    
    } // namespace str
    
    template <>
    void str::putCpNeT<2> (wchar_t*& p, unsigned long aCp)
    {
        if (aCp < U16_2WORD_MIN) {  // 1 word
            *(p++) = static_cast<wchar_t>(aCp);
        } else if (aCp <= U16_2WORD_MAX) {    // 2 words
            aCp -= U16_2WORD_MIN;
            // Hi word
            const wchar_t lo10 = aCp & 0x3FF;
            const wchar_t hi10 = aCp >> 10;
            *(p++) = static_cast<wchar_t>(0xD800 | hi10);
            *(p++) = static_cast<wchar_t>(0xDC00 | lo10);
        }
    }
    
    void str::appendCp(std::wstring& s, unsigned long aCp)
    {
        wchar_t c[5];
        wchar_t* end = c;
        putCpNe(end, aCp);
        s.append(c, end);
    }
    Ответ написан
    Комментировать
  • Как мне записать конечный результат деления?

    @Mercury13
    Программист на «си с крестами» и не только
    В зависимости от того, какого происхождения числа, можно поступать так.

    1. Работать с погрешностью. Например.
    q := X1 / X2;
    if abs(q - Round(q)) < 1e-5 then ...

    Я в основном сейчас на «си с крестами» и непривычка не брать условие в скобки :)

    2. Работать в рациональных числах.
    type
      TRatio = record
        Num, Den : integer;
      end;

    Думаю, сами сможете написать операции ±×/ и, если надо, сокращение.

    3. Работать в фиксированной запятой — например, перевести рубли в копейки.
    var
      X1 : integer = 100;
      X2 : integer = 20;
    
    if X1 mod X2 = 0 then ...


    4. Работать в десятичной длинной арифметике. Это уже совсем «большая пушка», и может быть что-то типа
    type
      TDecFloat = record
        mantissa : uint64;  // например, от 1e17 до 1e18
        order : integer;
        sign : boolean;
      end;

    Примерно так можно сделать калькулятор, работающий в десятичной системе и переводящий в extended и обратно, если, например, нужно взять синус. Погрешность перевода для трансцендентных функций, разумеется, будет, зато 0,2 в такой системе — это точное 0,2, и это важно для калькуляторов: он вычислит в точности то, что человек вычислит ручкой на бумаге.

    ВНИМАНИЕ! Для методов 2,3,4 придётся переработать всю цепочку, через которую появляются 1 и 0,2. В float/double нет числа 0,2, и точка.
    Ответ написан
  • Можете помочь найти ошибку в коде?

    @Mercury13
    Программист на «си с крестами» и не только
    1. 1/2 = 0, надо писать 1.0/2.0 или просто 0.5.
    2. В printf немного другие правила, чем в scanf, и надо
    printf_s("max = %f\n", max);
    Ответ написан
    Комментировать
  • Может ли код(определение) в заголовочных файлах быть вынесен в shared library?

    @Mercury13
    Программист на «си с крестами» и не только
    Надо сделать CPP-файл, в которые перенести как можно больше кода из программы. И код производят:
    • Static- и глобальные переменные.
    • Нешаблонные, не-inline-функции.
    • Не-inline, полностью расшаблоненные функции template<>.
    • Не-extern объявление шаблона типа template class std::vector<int>.
    Мало того, эти четыре вещи ошибочно держать в хедерах — но этого, как ни странно, в нашей библиотеке и нет, ведь она полностью полагается на шаблоны. Но есть пара резервов.

    1. Функция в теле класса автоматически становится inline, и, я бы сказал, что-нибудь типа AsynchronousReader::init было бы ошибкой держать inline’ом. По-хорошему, его надо в CPP. Но это довольно небольшая часть кода.
    2. Можно также наиболее распространённые версии классов/функций залить в SO. Для этого их надо вынести из тел классов и поступить примерно так.
    // H
    template <int x>
    void foo () { std::cout << x << std::endl; }
    
    extern template void foo<2>();
    
    // CPP
    template void foo<2>();
    Ответ написан
    Комментировать
  • Qt+QMake: как задать настройки компиляции для конкретного файла?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    И снова приходится отвечать самому.

    #pragma GCC optimize("O1")
    #pragma GCC optimize("no-lto")
    Ответ написан
    Комментировать
  • Как вывести результат этой функции?

    @Mercury13
    Программист на «си с крестами» и не только
    EOF — это маркер «файл закончился, данных больше нет». Обычно getchar даёт цифры от 0 до 255, а EOF — значение вне этих пределов (вообще-то −1).
    Консоль никогда не кончается, но конец файла можно сделать, нажав Ctrl+Z.

    Правильно писать int c; int r[]; int s[]; или int c, r[], s[];. Но в любом случае перед нами статический массив и ему надо дать размер.

    Иногда бывают массивы без размера — когда мы не заводим память, а просто говорим: «перед нами какой-то отрезок памяти». Например.
    void doSmth(int a[]) {}  // передаём в функцию отрезок памяти неизвестной длины
    int x[5];
    doSmth(x);
    
    extern int b[];  // компилятор рассматривает b как отрезок памяти неизвестной длины.
    int b[5];    // …и только линкер подставит на место b настоящий массив

    В Java массивы не статические и им размер дают тогда, когда выделяют им память.
    int[] x = new int[5];    // повторяю, это не Си++, а Java!

    Но это уже офтоп.
    Ответ написан
    8 комментариев
  • Как добавить перенос на новую строку?

    @Mercury13
    Программист на «си с крестами» и не только
    Я добавлю к Александр .
    В отличие от Си, где условие цикла каждый раз вычисляется полностью, в Паскале вторая граница for вычисляется один раз и запоминается.
    Потому длина строки меняется, а мы ходим до самой первой.

    К тому же вы неправильно решаете задачу. Никакой там не одной строкой. В ответе сервера концы строк LF, а надо CR+LF. Вот функция (крайне неоптимизированная), которая приводит концы строк к единому виду независимо от того, какие там стоят.
    function NormalizeEol(const s : string) : string;
    begin
      Result := StringReplace(s, #13#10, #10, [rfReplaceAll]);
      Result := StringReplace(Result, #13, #10, [rfReplaceAll]);
      Result := StringReplace(Result, #10, #13#10, [rfReplaceAll]);
    end;
    Ответ написан
    Комментировать
  • Можете объяснить логику Python умножения чисел?

    @Mercury13
    Программист на «си с крестами» и не только
    Так устроены float и double: они двоичные, и в них точно представляются только числа вида k·2−n. 0,4 не таково, у него в знаменателе пятёрка.
    Для большинства инженерных расчётов и игр это нормально. А вот если надо так, как подсчитал бы бухгалтер на бумаге (например, пишете калькулятор) — работайте с десятичным длинным.

    UPD. Наконец нашёл ту статью, какую хотел.
    www.delphikingdom.com/asp/viewitem.asp?catalogid=1217
    www.delphikingdom.com/asp/viewitem.asp?catalogid=374
    Ответ написан
    Комментировать
  • Почему в Си работают локальные функции?

    @Mercury13
    Программист на «си с крестами» и не только
    Очевидно, расширение GNU.
    MinGW, даже с ключом -std=c99, OK.

    Причём работает только в режиме Си. MinGW/Cи++
    C:\TestApps\NestedFunction3\main.cpp|7|error: a function-definition is not allowed here before '{' token|

    Embarcaredo x86 (Borland):
    [bcc32 Error] File1.c(7): E2141 Declaration syntax error

    Embarcadero x64 (clang):
    [bcc64 Error] File1.c(6): expected ';' at end of declaration
    Ответ написан
    1 комментарий
  • Какой использовать алгоритм?

    @Mercury13
    Программист на «си с крестами» и не только
    Очень важный вопрос. Может ли содержимое папки попасться раньше, чем сама папка? Для простоты считаем, что нет, и что вы нашли библиотеку для JSON.
    Нужны два объекта: дерево (самодельный) и словарь ID (map: id → развилка дерева).
    Для каждого элемента…
    1. По parent id через словарь находим, куда его впихнуть. Если не нашли — вывести ошибку.
    2. Если folder: создать развилку, присвоить ID, вписать её в словарь ID.
    3. Если не folder: создать лист, присвоить ID и вписать в словарь ID (если надо по какой-то другой причине).
    Я плохо знаю Си с диезом, так что поправляйте меня.
    class Node {
      List<Node> children;
      List<Leaf> leaves;
    }
    
    class Leaf {
      // в нём может быть что угодно
    }
    
    class Tree {
      Node root;
    }
    
    Tree tree;
    Dictionary<string, Node> idDic;  // считается, что словарь нужен только на разбор JSON,
       // и он временный
    Ответ написан
    Комментировать
  • Как посчитать количество совпадающих символов в обоих строках?

    @Mercury13
    Программист на «си с крестами» и не только
    3 тоже есть, так что правильный ответ 3. Ошибка тройная.
    for(size_t z = 0; z < b.length(); z++){
            if(a.find(b[z]) != std::string::npos){

    1. Индексы строк в STL беззнаковые, и компилятор может ругаться на сравнение знакового целого и беззнакового.
    2. На что тут 4, если есть s.length()
    3. Знак «не найдено» — std::string::npos.
    Ответ написан
    3 комментария
  • C++ QT почему не работает запрос к sql Lite DB?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, ваше решение неуниверсально и ваша ошибка — не заэкранировать идентификатор E-mail.
    Попробуйте [E-mail].
    (Часто используется экранирование `E-mail`, но в SqLite оно не катит, это специфика MySQL.)
    Ответ написан
    Комментировать
  • Простой пример одного и того же кода в ООП, функциональном и процедурном стиле?

    @Mercury13
    Программист на «си с крестами» и не только
    Просуммировать элементы std::vector<int>. Си++.

    Процедурный
    int sum = 0;
    for (int v : vec)
      sum += v;
    std::cout << sum << std::endl;


    ООП.
    class Accumulator
    {
    public:
      void feed(int value) { fSum += value; }
      int sum() const { return fSum; }
    private:
      int fSum = 0;
    }
    
    Accumulator acc;
    for (int v : vec)
      acc.feed(vec);
    std::cout << acc.sum() << std::endl;


    Функциональный (правда, слегка настоянный на шаблонах)
    int sum = std::accumulate(vec.begin(), vec.end(), 0);
    std::cout << sum << std::endl;


    UPD. Третий такой маленький, потому что в стандартной библиотеке нашли подходящую функцию.

    UPD2. А теперь представьте себе, что нужно вычислять не сумму, а что-то сложное — например, среднее и квадратичное отклонение. В процедурном придётся или раскрывать сложные формулы, или налаживать какие-то обобщения. Объектное меняется на раз-два. В функциональном придётся менять функцию-шаблон, работающую над итератором.
    Ответ написан
    Комментировать
  • Почему в текст запроса вставляется exec?

    @Mercury13
    Программист на «си с крестами» и не только
    Это связано с версией клиента MS SQL. Несколько вариантов переписать триггер.
    ALTER TABLE table_name DISABLE TRIGGER tr_name
    ALTER  TRIGGER trigger_name  DISABLE
    Ответ написан
    Комментировать
  • Для чего существует short?

    @Mercury13
    Программист на «си с крестами» и не только
    Си рассчитан на всякие машины. У некоторых байт более 8 бит — то есть к 8-битному октету обращаются как к битовой маске. Какие-то 16-битные, какие-то 32-битные.
    По всей видимости, int когда-то был «системным размером», коим сейчас является size_t.
    А char, short, long, long long — это 1/2/4/8 байт.
    Ваши знания «int равен 2 байтам» устарели — на современных машинах int равен 4 байтам.
    printf("%d\n", (int)(sizeof(int) * 8));
    Ответ написан
    9 комментариев