Страниц: 1 2 [3] 4 5
  Печать  
Автор Тема: Работа через USB с FlirOne Gen 2  (Прочитано 4741 раз)
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #30 : Мая 01, 2017, 02:00:31 pm »

Программа для обработки полученных RAW-файлов изображений.

Записан

И день и ночь в пути
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #31 : Мая 01, 2017, 09:04:49 pm »

Откуда столько спама стало валить?  Embarrassed
Записан

И день и ночь в пути
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #32 : Мая 29, 2017, 03:26:40 pm »

Хоть и не тепловизор, но тоже связанное с измерением температуры USB-устройство. Smiley

Валялся на работе китайский термодатчик для USB модели TEMPer V1.4. Почему бы и его не подключить по USB в QNX и заодно писать и температуру вокруг стенда? Подключил. Но датчик тоже с норовом - может с первого раза не запуститься. А на одном компьютере ни в какую не пожелал работать - один интерфейс появляется при подключении, а вот на втором интерфейсе у QNX ошибка usb_attach().
Вот что получилось:
Записан

И день и ночь в пути
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #33 : Июля 07, 2017, 10:51:46 am »

Меня на том же хабре часто ругали за неиспользование const вместо #define. Мол, #define вне модуля живёт (почти всегда это, правда, хорошо) и может быть переопределена незаметно в другом модуле. Всё это так, но вот смотрите какую фишку я сегодня словил, использовав именно глобальную переменную модуля (с const) для того, чтобы запереть объявления команд внутри модуля. Есть класс, он существует глобально. В его конструкторе инициализируется вектор списка команд. Вот так:

Код:
#include "cthreadserver.h"

CThreadServer cThreadServer;//серверный поток

//команды серверу
const string Command_Login="LOGIN=";
const string Command_Password="PASSWORD=";
const string Command_Connect="CONNECT";

CThreadServer::CThreadServer(void)
{
//инициализируем список команд
 vector_string_command.push_back(Command_Login);
 vector_string_command.push_back(Command_Password);
 vector_string_command.push_back(Command_Connect);
}

В конструкторе CThreadServer все Command равны пустой строке. Smiley Если же обменять местами объявления CThreadServer cThreadServer и команд, то инициализация проходит на ура. То есть, компилятор в своём порядке вызывает создание объектов (что логично) и к моменту вызова конструктора CThreadServer остальные объекты нифига не инициализированы. Просто отличный способ прострелить ногу! Smiley
Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #34 : Июля 07, 2017, 01:19:24 pm »

Просто отличный способ прострелить ногу! Smiley
Порядок инициализации  - это базовая вещь (которую необходимо знать/помнить) языка.
Хотите уменьшить риски от "прострелов ног" в этой области - перестаньте создавать глобальные переменные!!!
Нужны константные объекты инициализации - переместите их внутрь класса который их будет использовать (при этом их инициализацию можно начиная с С++11 переместить внутрь хедера класса). Не хотите получить оверхед за счет множества таких констант в классе - делайте статические константные объекты класса (а лучше всего статические методы возвращающие статические константные объекты метода, или constexpr методы/значения). Но не глобальные переменные!!! В 2017 году-то ..
Как вариант, так:

Код:
// хедер
class CThreadServer
{
public: // typedefs

  using Command = std::string;
  using CommandVector = std::vector<Command>;

public: // static

  static const CommandVector& getDefaultCommands();
  static const Command & getCommand_Login();
  static const Command & getCommand_Password();
  static const Command & getCommand_Connect();
};

// cpp -модуль
namespace
{
  CThreadServer::CommandVector generateDefaultCommands()
  {
    return CThreadServer::CommandVector {
                 CThreadServer::CommandVector::getCommand_Login(),
                 CThreadServer::CommandVector::getCommand_Password(),
                 CThreadServer::CommandVector::getCommand_Connect(),
             };
  }
};

const CThreadServer::CommandVector& CThreadServer::getDefaultCommands()
{
  static const CommandVector retCommands = generateDefaultCommands();
  return retCommand;
}

const CThreadServer::Command & CThreadServer::getCommand_Login()
{
    static const std::string retCommand("LOGIN=");
    return retCommand;
}

const CThreadServer::Command & CThreadServer::getCommand_Password()
{
    static const std::string retCommand("PASSWORD=");
    return retCommand;
}

const CThreadServer::Command & CThreadServer::getCommand_Connect()
{
    static const std::string retCommand("CONNECT=");
    return retCommand;
}

// конструктор
CThreadServer::CThreadServer()
 : vector_string_command(getDefaultCommands())
{
}

Конечно, нужно учитывать, что статические переменные в  многопоточных приложениях имеют свои проблемы инициализации. Но они тоже решаются - в зависимости от того, какими средства языка вам доступны (и какой стандарт). Но для описанной Вами проблемы (где инициализация объекта в одном потоке происходит раньше чем инициализация используемых глобальных переменных) - вполне себе решением будет.
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #35 : Июля 07, 2017, 01:43:57 pm »

Цитировать
Порядок инициализации  - это базовая вещь (которую необходимо знать/помнить) языка.
Хотите уменьшить риски от "прострелов ног" в этой области - перестаньте создавать глобальные переменные!!!

Порядок инициализации, это конечно, здорово, но только можно просто не заметить, кто должен быть создан первым, а кто вторым и просто внести в программу в произвольном месте.
Откуда глобально созданный сервер? Мне вот надо чтобы класс документа знал о классе сервера, а сервер знал о документе и получал при инициализации   указатель на него. Иными словами, перекрёстные ссылки с взаимным включением в h-файлы h-файлов друг-друга (в объявлении классов каждого объекта требуется знание о другом объекте). Зачем мне так? А потому что запускать сервер должен документ. При этом сервер должен через этот документ и общаться. И всё, что я придумал, так это серверу документ в h-файл подключить, а документу (который динамически создаётся MFC) подключить в его cpp-файле сервер, созданный глобально. В этом случае проблема исчезает, но появляется глобально созданный сервер.

Цитировать
Нужны константные объекты инициализации - переместите их внутрь класса который их будет использовать (при этом их инициализацию можно начиная с С++11 переместить внутрь хедера класса). Не хотите получить оверхед за счет множества таких констант в классе - делайте статические константные объекты класса (а лучше всего статические методы возвращающие статические константные объекты метода, или constexpr методы/значения).

Это очень захламляет класс.
Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #36 : Июля 07, 2017, 02:26:28 pm »

Порядок инициализации, это конечно, здорово, но только можно просто не заметить, кто должен быть создан первым, а кто вторым и просто внести в программу в произвольном месте.
Пишите на другом языке (кстати на пример каком, где порядок инициализации может быть "произвольным" ?)

Цитировать
Откуда глобально созданный сервер? Мне вот надо чтобы класс документа знал о классе сервера, а сервер знал о документе и получал при инициализации   указатель на него. Иными словами, перекрёстные ссылки с взаимным включением в h-файлы h-файлов друг-друга (в объявлении классов каждого объекта требуется знание о другом объекте). Зачем мне так? А потому что запускать сервер должен документ. При этом сервер должен через этот документ и общаться. И всё, что я придумал, так это серверу документ в h-файл подключить, а документу (который динамически создаётся MFC) подключить в его cpp-файле сервер, созданный глобально. В этом случае проблема исчезает, но появляется глобально созданный сервер.
Все что гарантируется при инициализации глобальных переменных - это лишь порядок инициализации внутри модлуля который их использует. Остальное - как повезет.
Поэтому - не используйте глобальные переменные, если вы планируете их использовать в разных модулях или собираетесь игнорировать порядок использования от порядка инициализации.
Иначе, давайте еще вспомним кучу возможностей - например не виртуальный деструктор в полиморфном классе. Дефолтный конструктор копирования для объектов которые копировать нельзя вообще (мютексы, потоки и другие содержащие референсы на системыне ресурсы классы) или которые копировать можно, но не поправилам дефолтного.
Так что Ваш аргумент - "константные переменные плохо, потому что если они глобальные то можно написать такоееее" - некоректен. Просто не пишите специально вот "такоеее".

Цитировать
Это очень захламляет класс.

Во первых, это был пример использования (один из вариантов).
Во вторых, никто не обязывает хранить это все внутри одного класса. Создайте отдельный класс комманд и не храните их внутри класса-потока
В третьих, я честное слово - не телепат. Для меня не известно, насколько Вы хотите чтобы команды были доступны для других модулей (являются они видимы за предлом класса или они только для внутренного использования). С моей колокольни - они должны быть видимы и доступны. Но если нет желания захломлять интерфейс класса вообще, команды только для внутреннего использования - то они да, выносятся из класса и  помещаются только в cpp-unit. Вэтом юните, в анонимном неймспейсе, делается один констэкспр метод или метод возвращающий константную ссылку на статический "локальный" объект.
Код:

// cpp-unit
namespace
{
  const Command& getCommand_Login()
  {
      static const std::string retCommand("LOGIN=");
      return retCommand;
  }

// ......

  const CommandVector& getDefaultCommands()
  {
    static const CommandVector retCommands{
                 getCommand_Login(),
                 getCommand_Password(),
                 getCommand_Connect(),
             };
     return retCommands;
  }
};

// конструктор
CThreadServer::CThreadServer()
 : vector_string_command(getDefaultCommands())
{
}
Правда же, и Ваш класс не пострадал )

Для меня захламление вот это вот
Цитировать
ThreadServer::CThreadServer(void)
{
//инициализируем список команд
 vector_string_command.push_back(Command_Login);
 vector_string_command.push_back(Command_Password);
 vector_string_command.push_back(Command_Connect);
}
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #37 : Июля 07, 2017, 05:11:05 pm »

Цитировать
Пишите на другом языке (кстати на пример каком, где порядок инициализации может быть "произвольным" ?)

Да при чём же тут это? Вся штука в том, что использование const-переменных вместо макросов порождает свои собственные проблемы.

Цитировать
Поэтому - не используйте глобальные переменные, если вы планируете их использовать в разных модулях или собираетесь игнорировать порядок использования от порядка инициализации.

lastcross, я всё это знаю. Smiley Дело тут в другом. Я-таки решил заменить макросы на константы в своей новой программе (почему бы и не попробовать сделать, как советуют многочисленные апологеты книжек Александреску и ему подобных? Вдруг код и вправду станет гораздо читабельнее и удобнее для работы с ним?) и совершенно вылетело из головы, что они тоже будут инициализироваться в своём порядке. Запустил программу - не проходит авторизация. Опа, а ведь константы же тоже инициализируются не сами по себе. Надо будет это не упустить из виду в будущем.

Цитировать
Так что Ваш аргумент - "константные переменные плохо, потому что если они глобальные то можно написать такоееее" - некоректен. Просто не пишите специально вот "такоеее".

Вся штука в том, что вот именно как глобальные переменные самое очевидное как использовать константы вместо макросов. В модуле может вообще кроме класса ещё какая функция потока быть и ей эта константа очень нужна. Ну спрячете в константу в класс, а поток её как забирать должен тогда? Как дружественная функция что ли? Smiley

Цитировать
Во вторых, никто не обязывает хранить это все внутри одного класса. Создайте отдельный класс команд и не храните их внутри класса-потока

Так не хочется на каждый чих по классу-то создавать. Оно того не стоит. Используется ровно один раз в функции поиска команды и на этом всё.  Undecided

Цитировать
Для меня не известно, насколько Вы хотите чтобы команды были доступны для других модулей

Нет, они только для внутреннего использования классом сервера. С тем, что вы предложили вот в чём проблема - удобно когда список таких настроек сгруппирован и идёт один к одному, например, в начале модуля. Одна строчка - один параметр. В случае отдельных классов так не получается.

Цитировать
Для меня захламление вот это вот

Я так понимаю, вы любите функциональный подход (это я вспомнил, как вы время с помощью лямбда-функции измеряли)? Smiley
У "этого вот" есть наглядность, тогда как у vector_string_command(getDefaultCommands()) с наглядностью немного сложнее - нужно раскручивать функции одну за другой, чтобы наконец, придти к списку инициализации. И всё это ради одного-единственного места, где всё это инициализируется.

А так - спасибо за идеи; они местами интересны. К сожалению, мой VC6 (да, я всё ещё с него не ушёл) не позволяет инициализировать константы в классе.
Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #38 : Июля 07, 2017, 05:57:51 pm »

Да при чём же тут это? Вся штука в том, что использование const-переменных вместо макросов порождает свои собственные проблемы.

Неправда же! Уберите у себя const и получите ровно такой же "выстрел"! Речь не о конст, а порядке инициализации вообще и о правилах инициализации именно глобальных переменных!

Цитировать
Вдруг код и вправду станет гораздо читабельнее и удобнее для работы с ним?) и совершенно вылетело из головы, что они тоже будут инициализироваться в своём порядке. Запустил программу - не проходит авторизация. Опа, а ведь константы же тоже инициализируются не сами по себе. Надо будет это не упустить из виду в будущем.

Еще раз перечитайте то что я написал выше. Да и переход от одного решения к другому, не всегда делается влоб (очевидно).

Цитировать
Вся штука в том, что вот именно как глобальные переменные самое очевидное как использовать константы вместо макросов. В модуле может вообще кроме класса ещё какая функция потока быть и ей эта константа очень нужна. Ну спрячете в константу в класс, а поток её как забирать должен тогда? Как дружественная функция что ли? Smiley
Реально удививли. Может быть так?
Код:
// хедер команд
namespace command
{
    //
    using CommandName = std::string;
    using CommandVector = std::vector<CommandName>;
    //....
   
    class Server
    {
    public:
        static const CommandVector& getDefaultCommands();
        static const Command & login();
        static const Command & password();
        static const Command & connect();
    }
};

// cpp-unit команд
using namespace command;
#include "command/server.h"

const CommandVector& Server::getDefaultCommands()
{
    static const CommandVector retCommands{
                     login(),
                     password(),
                     connect(),
                };
    return retCommands;   
}
// и дальше по анологии


// хедер класса для потока серверного (девственно чист и не захламлен)
class CThreadServer
{
    //...
};

// cpp -модуль класса для потока серверного
#include "ServerThread.h"
#include "command/server.h"

// конструктор
CThreadServer::CThreadServer()
 : vector_string_command(command::Server::getDefaultCommands())
{
}
Как видите - обошлись без друзей, функции возвращают коснтантные ссылки (то есть объекты не изменяемые), целевой класс не захламлен, а пользователю ненужно думать - глобальная это переменная или нет (И - инкапсуляция)

Цитировать
Так не хочется на каждый чих по классу-то создавать. Оно того не стоит. Используется ровно один раз в функции поиска команды и на этом всё.

Смотрите решение - где команды в cpp-unit-е в отдельном анонимном неймспейсе (его я приводил ранее). Другое дело когда, пользователь класса захочет через интерфейс выполнить следующее (совершенно в третьем cpp-юните)
Код:
#include "ServerThread.h"
#include "command/server.h"

//...
void onConnect()
{
//....
  mServerThread->execute(command::server::connect());
//...
}

Как это будет выглядеть в Вашем случае с глобальной переменной (которая сокрыта и не захломляет ничего) ?) Вы же не планируете прям вбивать строку в вызов execute? )) Например так?
Код:
  mServerThread->execute("CoNect");

Цитировать
С тем, что вы предложили вот в чём проблема - удобно когда список таких настроек сгруппирован и идёт один к одному, например, в начале модуля. Одна строчка - один параметр. В случае отдельных классов так не получается.
Не понял о чем Вы, но уверен что проблемы с этим в моем решении не будет.

Цитировать
Я так понимаю, вы любите функциональный подход (это я вспомнил, как вы время с помощью лямбда-функции измеряли)? Smiley
У "этого вот" есть наглядность, тогда как у vector_string_command(getDefaultCommands()) с наглядностью немного сложнее - нужно раскручивать функции одну за другой, чтобы наконец, придти к списку инициализации. И всё это ради одного-единственного места, где всё это инициализируется.

Нет, ваше решение заставляет инициализировать вектор дважды: конструирует пустой вектор, а после внутри конструктора добавляет какждый элемент вконец (заставляя вектор переалоцироватся). Мое решение - позволяет инициализировать вектор один раз и алоцировать его всего единожды (так как идет каопирование вставкой, а возможно даже и без копирования если произойдет мовмент). Это так, если касаться производительности.
Кроме того, В случае рефакторинга, когда потребуется добавить новый конструктор с каким-либо параметром, вам придеться и там "заполнять вектор" таким же способом (или каким-либо другим). Это скорее всего приведт к тому - что у вас будут два разных конктруктора с похожим телом, сопровождение которых может привести в дальнейшем к ошибке (набор команд инициализации нужно изменить - этот набор придеться проводить во всех конструкторах класса, у меня же - в одном методе).
Предположу и третий вариант, когда по каким-то причинам вы откажетесь от вектора команд в пользу хеш-контейнера (понадобится быстро находить команду из списка). В таком случае, количество необходимых изменений в коде будет значительным, по сравнению когда инициализация происходит в инициализационном списке конструктора.

А насчет наглядности - это дело зависит от хорошо прдуманого названия метода. Разумеется я не стал вникать какой смысл имеет именно этот список команд. Но его можно назвать как authorizeCommand() вместо getDefaultCommands. Имхо, мне проще понимать что этот метод всегда генерирует набор команд для авторизации, чем вникать почему в конструкторе именно  такой набор команд. А вот когда мне потребуется вникуть какие команды идут на авторизацию - я раскрою метод и увижу. Сегодня это три команды - а завтра 40 (и совсем другие). Зачем мне это видеть в конструкторе?. А если кроме конструктора нужно будет повторить еще раз этот набор?
Цитировать
А так - спасибо за идеи; они местами интересны.
Всегда пожалуйста =)

з.ы.: немного внес исправления в пример кода в именовании методов
« Последнее редактирование: Июля 07, 2017, 06:10:16 pm от lastcross » Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #39 : Июля 07, 2017, 06:27:32 pm »

Цитировать
Неправда же! Уберите у себя const и получите ровно такой же "выстрел"! Речь не о конст, а порядке инициализации вообще и о правилах инициализации именно глобальных переменных!

Эх, похоже, вам нужно формулировать максимально точно о чём идёт речь, иначе вы обращаете внимание совсем не на то, о чём сообщение, а на какие-либо незначительные детали, относящиеся к частному случаю. Embarrassed Хорошо. Тогда скажу так: использование любых глобальных переменных вместо макроопределений порождает вышеуказанную проблему последовательности инициализации. Макроопределения такой проблемы не порождают.

Цитировать
Реально удививли. Может быть так?

Так нет же функции потока. Undecided
Я вот о чём:
Код:
//функция потока
UINT ThreadServer(LPVOID pParam)
{
 //что-то делаем, и тут нужна константа, спрятанная внутри класса
 return(0);
}

...
//где-то там, внутри класса серверного потока мы запустили поток и передали ему указатель на себя:
void CThreadServer::Start(void)
{
 cWinThread_Thread=AfxBeginThread((AFX_THREADPROC)ThreadServer,this);
 cWinThread_Thread->m_bAutoDelete=FALSE;
}

Цитировать
Как это будет выглядеть в Вашем случае с глобальной переменной (которая сокрыта и не захламляет ничего) ?) Вы же не планируете прям вбивать строку в вызов execute? )) Например так?

Пока - никак. Smiley В настоящий момент названия команд принимаются по сети и не требуют использования где-то ещё.

Цитировать
Не понял о чем Вы, но уверен что проблемы с этим в моем решении не будет.

Я имею в виду вот что:
Код:
//код устройства
#define DEVICE_ID_BWFKP   7

//количество устройств
#define BWFKP_AMOUNT 1

//коды подтверждения
#define BWFKP_CONFIRM_CODE_OK    1
#define BWFKP_CONFIRM_CODE_ERROR 0

//коды режимов работы БВФКП

//запрос состояния
#define BWFKP_MODE_ID_WORKING 0x01
//включить АКУ
#define BWFKP_MODE_ID_ACU_ON 0x02
//включить ГБ №1
#define BWFKP_MODE_ID_UNIT_1_ON 0x03
//включить ГБ №2
#define BWFKP_MODE_ID_UNIT_2_ON 0x04
//включить ГБ №3
#define BWFKP_MODE_ID_UNIT_3_ON 0x05
//включить акселерометр №1
#define BWFKP_MODE_ID_ACS_1_ON 0x06
//включить акселерометр №2
#define BWFKP_MODE_ID_ACS_2_ON 0x07
//включить акселерометр №3
#define BWFKP_MODE_ID_ACS_3_ON 0x08
//включить акселерометр №4
#define BWFKP_MODE_ID_ACS_4_ON 0x09
//включить акселерометр №5
#define BWFKP_MODE_ID_ACS_5_ON 0x0A
//включить акселерометр №6
#define BWFKP_MODE_ID_ACS_6_ON 0x0B
//включить аккумуляторную батарею
#define BWFKP_MODE_ID_BAT_ON 0x0C
//включить контроль аккумуляторной батареи
#define BWFKP_MODE_ID_BAT_CONTROL_ON 0x0D
//включить ЦВ №1
#define BWFKP_MODE_ID_CW_1_ON 0x0E
//включить ЦВ №2
#define BWFKP_MODE_ID_CW_2_ON 0x0F
//включить ЦВ №3
#define BWFKP_MODE_ID_CW_3_ON 0x10
//включить ЭНЗУ
#define BWFKP_MODE_ID_ENZU_ON 0x11


//отключить АКУ
#define BWFKP_MODE_ID_ACU_OFF 0x12
//отключить ГБ №1
#define BWFKP_MODE_ID_UNIT_1_OFF 0x13
//отключить ГБ №2
#define BWFKP_MODE_ID_UNIT_2_OFF 0x14
//отключить ГБ №3
#define BWFKP_MODE_ID_UNIT_3_OFF 0x15
//отключить акселерометр №1
#define BWFKP_MODE_ID_ACS_1_OFF 0x16
//отключить акселерометр №2
#define BWFKP_MODE_ID_ACS_2_OFF 0x17
//отключить акселерометр №3
#define BWFKP_MODE_ID_ACS_3_OFF 0x18
//отключить акселерометр №4
#define BWFKP_MODE_ID_ACS_4_OFF 0x19
//отключить акселерометр №5
#define BWFKP_MODE_ID_ACS_5_OFF 0x1A
//отключить акселерометр №6
#define BWFKP_MODE_ID_ACS_6_OFF 0x1B
//отключить аккумуляторную батарею
#define BWFKP_MODE_ID_BAT_OFF 0x1C
//отключить контроль аккумуляторной батареи
#define BWFKP_MODE_ID_BAT_CONTROL_OFF 0x1D
//отключить ЦВ №1
#define BWFKP_MODE_ID_CW_1_OFF 0x1E
//отключить ЦВ №2
#define BWFKP_MODE_ID_CW_2_OFF 0x1F
//отключить ЦВ №3
#define BWFKP_MODE_ID_CW_3_OFF 0x20
//отключить ЭНЗУ
#define BWFKP_MODE_ID_ENZU_OFF 0x21
//отключить блокировку отключения ГБ №1
#define BWFKP_MODE_ID_UNIT_1_BLOCK_OFF 0x22
//отключить блокировку отключения ГБ №2
#define BWFKP_MODE_ID_UNIT_2_BLOCK_OFF 0x23
//отключить блокировку отключения ГБ №3
#define BWFKP_MODE_ID_UNIT_3_BLOCK_OFF 0x24

//задать значение константы (без записи во FLASH)
#define BWFKP_MODE_ID_SET_CONST 0x25
//считать текущее значение константы (текущее значение из ОЗУ)
#define BWFKP_MODE_ID_GET_CONST 0x26
//записать константы во FLASH
#define BWFKP_MODE_ID_FLASH_WRITE 0x27

//отключить систему
#define BWFKP_MODE_ID_SHUTDOWN 0x28
//разрешить отключение системы
#define BWFKP_MODE_ID_SHUTDOWN_BLOCK_OFF 0x29
//запретить отключение системы
#define BWFKP_MODE_ID_SHUTDOWN_BLOCK_ON 0x2A


//маски состояние реле
//состояние АКУ
#define BWFKP_RELAY_MASK_ACU_ON (1<<0)
//состояние ГБ №1
#define BWFKP_RELAY_MASK_UNIT_1_ON (1<<1)
//состояние ГБ №2
#define BWFKP_RELAY_MASK_UNIT_2_ON (1<<2)
//состояние ГБ №3
#define BWFKP_RELAY_MASK_UNIT_3_ON (1<<3)
//состояние акселерометра №1
#define BWFKP_RELAY_MASK_ACS_1_ON (1<<4)
//состояние акселерометра №2
#define BWFKP_RELAY_MASK_ACS_2_ON (1<<5)
//состояние акселерометра №3
#define BWFKP_RELAY_MASK_ACS_3_ON (1<<6)
//состояние акселерометра №4
#define BWFKP_RELAY_MASK_ACS_4_ON (1<<7)
//состояние акселерометра №58
#define BWFKP_RELAY_MASK_ACS_5_ON (1<<8)
//состояние акселерометра №6
#define BWFKP_RELAY_MASK_ACS_6_ON (1<<9)
//состояние батареи
#define BWFKP_RELAY_MASK_BAT_ON (1<<10)
//состояние контроля батареи
#define BWFKP_RELAY_MASK_BAT_CONTROL_ON (1<<11)
//состояние ЦВ №1
#define BWFKP_RELAY_MASK_CW_1_ON (1<<12)
//состояние ЦВ №2
#define BWFKP_RELAY_MASK_CW_2_ON (1<<13)
//состояние ЦВ №3
#define BWFKP_RELAY_MASK_CW_3_ON (1<<14)
//состояние ЭНЗУ
#define BWFKP_RELAY_MASK_ENZU_ON (1<<15)
//состояние блокировки отключения гироблока №1
#define BWFKP_RELAY_MASK_UNIT_1_BLOCK_ON (1<<16)
//состояние блокировки отключения гироблока №2
#define BWFKP_RELAY_MASK_UNIT_2_BLOCK_ON (1<<17)
//состояние блокировки отключения гироблока №3
#define BWFKP_RELAY_MASK_UNIT_3_BLOCK_ON (1<<18)
//состояние блокировки отключения системы
#define BWFKP_RELAY_MASK_SHUTDOWN_BLOCK_ON (1<<19)

//маски состояния и допуска
//состояние АКУ
#define BWFKP_STATE_CONTROL_MASK_ACU_I (1<<0)
//состояние ГБ №1
#define BWFKP_STATE_CONTROL_MASK_UNIT_1_I (1<<1)
//состояние ГБ №2
#define BWFKP_STATE_CONTROL_MASK_UNIT_2_I (1<<2)
//состояние ГБ №3
#define BWFKP_STATE_CONTROL_MASK_UNIT_3_I (1<<3)
//состояние акселерометра №1
#define BWFKP_STATE_CONTROL_MASK_ACS_1_I (1<<4)
//состояние акселерометра №2
#define BWFKP_STATE_CONTROL_MASK_ACS_2_I (1<<5)
//состояние акселерометра №3
#define BWFKP_STATE_CONTROL_MASK_ACS_3_I (1<<6)
//состояние акселерометра №4
#define BWFKP_STATE_CONTROL_MASK_ACS_4_I (1<<7)
//состояние акселерометра №58
#define BWFKP_STATE_CONTROL_MASK_ACS_5_I (1<<8)
//состояние акселерометра №6
#define BWFKP_STATE_CONTROL_MASK_ACS_6_I (1<<9)
//состояние батареи
#define BWFKP_STATE_CONTROL_MASK_BAT_U (1<<10)
//состояние ЦВ №1
#define BWFKP_STATE_CONTROL_MASK_CW_1_I (1<<11)
//состояние ЦВ №2
#define BWFKP_STATE_CONTROL_MASK_CW_2_I (1<<12)
//состояние ЦВ №3
#define BWFKP_STATE_CONTROL_MASK_CW_3_I (1<<13)
//состояние ЭНЗУ
#define BWFKP_STATE_CONTROL_MASK_ENZU_I (1<<14)
//состояние ИПК
#define BWFKP_CONTROL_MASK_IPK_U (1<<15)

//множитель для ресурса батареи в БВФКП (перевод в проценты)
#define BWFKP_MULTIPLICATOR_RESOURCE_PROCENTS 1
//множитель для напряжения батареи в БВФКП (перевод в вольты)
#define BWFKP_MULTIPLICATOR_BATTERY_U 0.1
 
//номера устройств для коэффициентов коррекции тока и допусков во FLASH
#define BWFKP_FLASH_ACU 0
#define BWFKP_FLASH_UNIT_1 1
#define BWFKP_FLASH_UNIT_2 2
#define BWFKP_FLASH_UNIT_3 3
#define BWFKP_FLASH_ACS_1 4
#define BWFKP_FLASH_ACS_2 5
#define BWFKP_FLASH_ACS_3 6
#define BWFKP_FLASH_ACS_4 7
#define BWFKP_FLASH_ACS_5 8
#define BWFKP_FLASH_ACS_6 9
#define BWFKP_FLASH_CW_1 10
#define BWFKP_FLASH_CW_2 11
#define BWFKP_FLASH_CW_3 12
#define BWFKP_FLASH_ENZU 13
#define BWFKP_FLASH_BAT_U 14
#define BWFKP_FLASH_BAT_I 15
//#define BWFKP_FLASH_BAT 16

//номера коэффициентов полинома (i_out=a*i^3+b*i^2+c*i+d)
#define BWFKP_FLASH_A 0
#define BWFKP_FLASH_B 1
#define BWFKP_FLASH_C 2
#define BWFKP_FLASH_D 3
//номер допуска на максимальный потребляемый ток
#define BWFKP_FLASH_MAX_VALUE 4
//номер допуска на ток, достаточный чтобы устройство считалось включенным
#define BWFKP_FLASH_ON_VALUE 5
При таком оформлении просто приятно глазом просматривать настройки. А в случае с отдельным классом с методами Get что-то там это выглядит в данном случае не очень.  Cool

Цитировать
Нет, ваше решение заставляет инициализировать вектор дважды: конструирует пустой вектор, а после внутри конструктора добавляет какждый элемент вконец (заставляя вектор переалоцироватся).

Но это делается один раз при запуске, поэтому ровно ничего не стоит компьютеру. Вот ползанье по базе данных через ODBC без SQL (я его не знаю, но, возможно, придётся почитать про него и задействовать) - вот это точно будет влиять на скорость. Но тут я посмотрю по фактической работе программы и оценю размер базы. Smiley

Цитировать
Кроме того, В случае рефакторинга,

Он крайне маловероятен. Smiley Я бы сказал, он вероятен с вероятностью повторного значения GUID. Smiley
« Последнее редактирование: Июля 07, 2017, 06:29:10 pm от da-nie » Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #40 : Июля 07, 2017, 07:17:56 pm »

Цитировать
Эх, похоже, вам нужно формулировать максимально точно о чём идёт речь, иначе вы обращаете внимание совсем не на то, о чём сообщение
Ну этому была причина. Вы акцентировали неоднакратно внимание на инициализации именно const.

Цитировать
Макроопределения такой проблемы не порождают.
Зато легко можно получить невалидную иницализацию при переопределении макроса (без ошибок компилятора), например. И кроме того - я акцентирую внимание на том, что это известное поведение. И если человек решил уйти от "макросов-констант" в сторону константных переменных - то он не будет делать это влоб (через глобальные переменные)

Цитировать
Так нет же функции потока. Undecided
Код:
#include "command/server.h"
//функция потока
UINT ThreadServer(LPVOID pParam)
{
 using namespace command;
 // пользуйтесь наздоровье, без френдов и тому подобного
 const CommandName& connect = Server::connect();
 // или так, для с++11
 const auto& connect = Server::connect();
 //...
 return(0);
}

...
Единственный подводный камень для всего этого (действительно явное отличие от макросов в пользу их использования) - это только тот факт, что инициализация объектов которые будут разделяемы между потоками - не совсем потока безопасна. Для этого в С++11 добавлен thread_local. Для ранних версий - прийдеться делать какие либо дополнительные манупуляции (гарантирующие инициализацию до исполнения потока, или же посредством атомарных объектов обеспечить инициализацию). Но опять же все это решается гораздо проще когда у вас есть методы возвращающие констаты и инкапсулирующие инициализацию.

Цитировать
Как это будет выглядеть в Вашем случае с глобальной переменной (которая сокрыта и не захламляет ничего) ?) Вы же не планируете прям вбивать строку в вызов execute? )) Например так?

Здорово! Но не желаю вам поддерживать такой список команд, размазанный по всему коду в виде
Код:
auto currentCommand = extractCommandFromNetwork();
 if (currentCommand == "CONNECT=")
 {
 }


Цитировать
Я имею в виду вот что:
Код:
//код устройства
#define DEVICE_ID_BWFKP   7

//количество устройств
#define BWFKP_AMOUNT 1

//коды подтверждения
#define BWFKP_CONFIRM_CODE_OK    1
#define BWFKP_CONFIRM_CODE_ERROR 0
//....
При таком оформлении просто приятно глазом просматривать настройки. А в случае с отдельным классом с методами Get что-то там это выглядит в данном случае не очень.  Cool
Это фломастеры - а они разные на вкус и цвет. Если Вам так удобнее - пользуйтесь макросами. Лично для меня этот список - ужасный набор несгрупированых команд (с точки зрения возможностей С++).

Цитировать
Он крайне маловероятен. Smiley Я бы сказал, он вероятен с вероятностью повторного значения GUID. Smiley
Почему Вы вообще паритесь по поводу констант и макросов - если программу всеравно после выбрасывать =) ? Если человек задумывается что лучше использовать - макросы или константы, значит одна из причин - это вопросы возможности сопровождения и модификации программы в дальнейшем.
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #41 : Июля 07, 2017, 08:18:24 pm »

Ну,про недостатки макроопределений это и так понятно. Smiley

Цитировать
И если человек решил уйти от "макросов-констант"

Я просто решил попробовать под впечатлением от:
Цитировать
И еще. Я ваши статьи узнаю по внешнему виду исходников. Да. По этим ужасным простыням кода низкого качества, в котором отсутствует функциональное деление, использование констант и логичное именование переменных. Ваш код (если на него смотреть как на самостоятельную единицу ценности) годится только на выброс. Ну или в качестве наказания для других разработчиков.

1) у вас имеются длииииннные методы (эмпирическое правило — размер метода должен быть не более одного «экрана» текста — той области, которую можно охватить зрением, не переводя взгляд). Разбивка простыней на части помогает их структурировать.

2) многие данные по смыслу являются векторами. Вот и работайте с ними, как с векторами. Этим вы исключите копипаст и эффект последней строки при копипасте. Не волнуйтесь, компиляторы уже умеют раскручивать циклы. Посмотрите хотя бы на нашу с haqreu библиотеку для векторов и матриц.

3) если вместе с выполнением (2) начать именовать переменные содержательно, программу можно будет вообще читать как сказку, а не продираться через x1; x2; dx; и прочее.

4)константные данные следует помещать в const, а не толкать в дефайны.
Вот я и решил ну сделать просто как идеал в моём понимании. Smiley Правда, идеал, как обычно, никто никогда не показывает. Smiley А по поводу разбиения функции на короткие кусочки, я (и не только я) полагаю, что линейная последовательность не нуждается в разбиении. Smiley По переменным и структурированному коду он (и те, кто в личке написали с советами всё сделать классами (хотя я предупредил, что программа была изначально на чистом С и просто обёрнута классом при портировании)), судя по всему, не понял системы обозначений и разбивки на элементы. И опять-таки, даже самые простые данные почему-то все написавшие хотят видеть как сложные объекты (вектор тут математическое понятие - (x,y)). Ну и как обычно принято на хабре, на мой ответ комментариев, собственно по ответу, не последовало ни в личке, ни в статье (но на карме они отразились в сторону уменьшения, что показывает о сильно несогласных со мной, но боящихся высказаться и получить от кого-либо уменьшение уже своей кармы. Бред, конечно, с этой кармой, но вот трясутся за неё все там.). Smiley

Цитировать
Но опять же все это решается гораздо проще когда у вас есть методы возвращающие констаты и инкапсулирующие инициализацию.

Если так делать, тогда вообще можно вместо констант поставить не класс, а любую функцию со статической константной переменной. Undecided Но тогда мы просто вернёмся к обычным функциям, возвращающим параметр. Кстати,я не пробовал создать массив от результата такой функции. Roll Eyes Типа long Array[GetArraySize()];, если const long& GetArraySize(void) {static const long a=10; return(a)}; Надо проверить будет. Smiley

Цитировать
Но не желаю вам поддерживать такой список команд, размазанный по всему коду в виде

Нет, там сравнение в цикле. Для того и в вектор помещается.

Цитировать
Если Вам так удобнее - пользуйтесь макросами.

Я отталкивался от категоричного "4)константные данные следует помещать в const, а не толкать в дефайны.", потому и решил попробовать. Smiley

Цитировать
Почему Вы вообще паритесь по поводу констант и макросов - если программу всеравно после выбрасывать =) ? Если человек задумывается что лучше использовать - макросы или константы, значит одна из причин - это вопросы возможности сопровождения и модификации программы в дальнейшем.

Потому что я хочу получить тот самый идеальный код (который так любит Роберт Мартин), но далеко не со всем согласен из того, что он там рекомендует. Это с одной стороны. С другой появляется мысль попробовать сделать так, как рекомендуется - быть может, я ошибаюсь в ряде положений или не знаю ряд приёмов, при которых описанное тем же Мартином сильно улучшит код. Сопровождаться и модифицироваться этот код будет, а вот меняться идеология этого блока - нет. Это всего лишь сервер, выполняющий ряд операций над двумя базами данных по командам по сети от клиентских программ. Тут ясно, что класс сервера просто вещь в себе и шансов стать чем-то другим у него просто нет.
« Последнее редактирование: Июля 07, 2017, 08:24:06 pm от da-nie » Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #42 : Июля 07, 2017, 10:51:48 pm »

Цитировать
Ну,про недостатки макроопределений это и так понятно. Smiley
Это скорее не недостаток, это правило использования. У глобальных переменных есть свои правила (константных и не константных).
Недостаток это когда у макроса нельзя взять адрес, или когда он не ограничен областью видимости или когда он не контролируется в преобразовании типа и тд.. Эти ограничения вообще нельзя обойти - так как макросы разворачиваются до компиляции. Вот это и есть их недостатки (хотя и ряд достоинств именно в этом).
Цитировать
Я просто решил попробовать под впечатлением от ..

Все его комментарии важны в случае если программу планируют поддерживать и она не является примером академическим. Иногда у Вас мелькают фразы - что в большинстве случаев такое программам Вашим не светит. Если это не так - то следует прислушаться, потому как через пару лет все ваши алгоритмы никто поддерживать не станет. По причине - затруднений в чтении самой программы при переносе на другие платформы/языки.

Цитировать
А по поводу разбиения функции на короткие кусочки, я (и не только я) полагаю, что линейная последовательность не нуждается в разбиении.
ИМХО - Вы не правы. Даже если в функции есть только линейное исполнение (без циклов и условий), лучше воспринимается не одиночные атомарные команды (завязанные на имплементацию), а сгруппированные и логически связанные наборы команд в ограниченном количестве. Т.е. если функция содержит десяток простыней текста, всегда можно сгруппировать и свести функцию к десятку вызовов логических методов. Вы ранее упоминали слово "захламляет" - тут схожий принцип, большое количество команд, захламляет восприятие всей функции в целом.

Относительно использование классов, и что все хотят видеть в таком роде объекты. Это смотреть нужно в конкретном случае. Но да, очень часто хотят видеть объект типа Point и объект типа Size, а не объекты типа std::pair<int, int> или не дай Бог int x, y (которые размазаны по всему коду). Почему так? Ну понятно же над точкой  можно проделать любые операции характерные точке, а над Size - совсем другие (хотя и тот и другой может быть представлены как два int). Когда какая-то функция принимает в качестве параметра Point в нее будет затруднительно впихнуть Size. Но вообще без проблем это сделать если функция принимает только два int. Люди которые читают подобный код, тратят время не только что бы понять как автор решил проблему, а и на то чтобы понять что именно он передал в метод (например)

Цитировать
Если так делать, тогда вообще можно вместо констант поставить не класс, а любую функцию со статической константной переменной. Undecided
Но тогда мы просто вернёмся к обычным функциям, возвращающим параметр. Кстати,я не пробовал создать массив от результата такой функции. Roll Eyes Типа long Array[GetArraySize()];, если const long& GetArraySize(void) {static const long a=10; return(a)}; Надо проверить будет. Smiley
Нет, все не так. Или я Вас не понял что вы поставить хотите вместо классов.

Цитировать
Нет, там сравнение в цикле. Для того и в вектор помещается.
Опять же я, я не понимаю в чем был вопрос о френд-функции в контексте доступа к списку команд (пришедших по сети). В чем заключается такой доступ? Как он будет разделять одну команду от другой если не использует сравнение?)

Цитировать
Потому что я хочу получить тот самый идеальный код (который так любит Роберт Мартин), но далеко не со всем согласен из того, что он там рекомендует. Это с одной стороны. С другой появляется мысль попробовать сделать так, как рекомендуется - быть может, я ошибаюсь в ряде положений или не знаю ряд приёмов, при которых описанное тем же Мартином сильно улучшит код.

Идеальный код, это такой код который не вызывает вопросов ни у Вас, ни у ваших сотрудников которые будут его сопровождать (разумеется при этом не содержать ошибок). Так что советую не ориентироваться на кого-либо, если в Вашем окружении макросы воспринимаются легко. Если же, существуют вопросы или Вы планируете менять работу - то да, лучше придерживаться рекомендаций описанных выше. Про использования констант - я вам дал свои рекомендации (по крайней мере они решают проблему инициализации).
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #43 : Июля 09, 2017, 01:15:21 pm »

Цитировать
Если это не так - то следует прислушаться, потому как через пару лет все ваши алгоритмы никто поддерживать не станет. По причине - затруднений в чтении самой программы при переносе на другие платформы/языки.

Указанный комментарий относился к программе пасьянса "Косынка" (аналогичной той, что я здесь для QNX приводил, только перенесённую под Windows и с частично убранными магическими числами (частично - потому что просто лень было количество карт (их 52) задать отдельно. )), которая сама по себе очень простая и там максимум 200 строк отвечают за, собственно, игру. А проблемы с программами, обычно, не в понимании, что и как делает функция (это, как правило, очевидно из комментария или просто по виду функции), а в том, чтобы представить общую концепцию программы.
Скажем, вот функция:
Код:
//----------------------------------------------------------------------------------------------------
//рисование полов
//----------------------------------------------------------------------------------------------------
void CEngine_Base::DrawFloor(long sector_index,const SVisualPlanes &sVisualPlanes_Bottom)
{
 //параметры сектора
 long level=vector_CISectorPtr[sector_index]->GetDown();
 long texture=vector_CISectorPtr[sector_index]->GetCTextureFollow_Down_Ptr()->GetCurrentTexture().TextureIndex;
 long bright=vector_CISectorPtr[sector_index]->GetLighting();
 long z=static_cast<long>((PlayerZ-level)*(WindowHeight/2));

 long screen_min_x;
 long screen_max_x;
 long x;
 long y;
 screen_min_x=sVisualPlanes_Bottom.MinX;
 screen_max_x=sVisualPlanes_Bottom.MaxX;
 if (screen_max_x<screen_min_x) return;
 long y_top=sVisualPlanes_Bottom.TopY[screen_min_x];
 long y_bottom=sVisualPlanes_Bottom.BottomY[screen_min_x];
 for(y=y_top;y<=y_bottom;y++) X_Table[y]=screen_min_x;
 for(x=screen_min_x;x<=screen_max_x;x++)
 {
  long zd;
  long top_plane_y=sVisualPlanes_Bottom.TopY[x];
  long bottom_plane_y=sVisualPlanes_Bottom.BottomY[x];
  if (bottom_plane_y<top_plane_y) continue;//при возможных пропусках точек на границах (а они есть), алгоритм развалится

  //если верхняя линия поднимается
  while(top_plane_y<y_top)
  {
   y_top--;
   X_Table[y_top]=x;
  }
  //если нижняя линия опускается
  while(bottom_plane_y>y_bottom)
  {
   y_bottom++;
   X_Table[y_bottom]=x;
  }

  //если верхняя линия опускается
  zd=(y_top-WindowYCenterWithOffset)+1;
  while(y_top<top_plane_y)
  {
   long dist=z/zd;
   long scale=dist/zd;
   DrawTextureLine(dist,scale,bright,texture,y_top,X_Table[y_top],x-1);
   y_top++;
   zd++;
  }

  //если нижняя линия поднимается
  zd=(y_bottom-WindowYCenterWithOffset)+1;
  while(y_bottom>bottom_plane_y)
  {
   long dist=z/zd;
   long scale=dist/zd;
   DrawTextureLine(dist,scale,bright,texture,y_bottom,X_Table[y_bottom],x-1);
   y_bottom--;
   zd--;
  }
 }
 //заливаем промежуток между top и bottom
 long zd=(y_top-WindowYCenterWithOffset)+1;
 for(y=y_top;y<=y_bottom;y++,zd++)
 {
  long dist=z/zd;
  long scale=dist/zd;
  DrawTextureLine(dist,scale,bright,texture,y,X_Table[y],screen_max_x);
 }
}
Вот не понимая концепции её работы в рамках программы, потребуется позеленеть, чтобы понять, что вообще происходит в этой функции и как она работает. Хотя что делает с переменными сама функция понятно совершенно. Но вот почему она делает именно так останется загадкой. Без объяснения алгоритма это понять по исходному коду будет очень и очень не просто.
Вот есть у меня исходник Quake-1 для PSP и очень непросто (даже со всеми введёнными Кармаком типами) понять, как именно он работает. Тут поможет только описание структуры программы и UML-диаграммы.

Цитировать
ИМХО - Вы не правы.

Ну, я тогда перефразирую, что делать слишком большие функции тоже плохо, ровно как и плодить кучу мелких по принципу, лишь бы в экран влезала каждая. Дело в том, что обычно по ходу функции готовятся данные для финального действия и в случае вызовов мелких функций это требует передачи им этих накопленных данных (что может быть весьма непросто, вплоть до создания самостоятельного объекта этих данных), а кроме того, большое количество функций порождает спагетти, где требуется раскручивать программу по кусочкам и затрудняет понимание. Иными словами, во всём нужна мера. Smiley Вот тут (ссылка) есть прекрасный разбор сказки о Курочке Рябе в приёмах деления на функции: Smiley
Цитировать
Естественно, разбираться в 2000 строчках кода сложнее, чем в 20. Кто бы спорил? Но если 20 умножить на 100, то 2000 не получится. Добавится необходимость помнить, как эта беда складывается в дерево вызовов. То есть помнить, что «Мышка бежала» получает управление через функцию «ЯичкоРазбито», которая стартует после «Снесла она яичко не простое, а золотое» в функции «ПолучениеЯичка» и перед «Не золотое, а простое» в функции «Обещание».

Цитировать
Люди которые читают подобный код, тратят время не только что бы понять как автор решил проблему, а и на то чтобы понять что именно он передал в метод (например)

Это, безусловно, имеет смысл. Но также, в зависимости от ситуации.

Цитировать
Нет, все не так. Или я Вас не понял что вы поставить хотите вместо классов.

Честно говоря, я уже запутался в порядке предложений. Но я имею в виду вот что.
Вот это:
Код:
// хедер команд
namespace command
{
    //
    using CommandName = std::string;
    using CommandVector = std::vector<CommandName>;
    //....
    
    class Server
    {
    public:
        static const CommandVector& getDefaultCommands();
        static const Command & login();
        static const Command & password();
        static const Command & connect();
    }
};
В таком случае не требуется создания класса команд. Точно также можно в пространстве имён Command задать все эти функции без класса в отдельном модуле и при первом же вызове они будут инициализированы. Но вот что ещё плохо при использовании функций, возвращающих константу: я не уверен, что цикл for (long n=0;n<constants::GetMaxItem();n++) не будет любым компилятором вызывать с каждой итерацией цикла функцию (на -o3 может и не будет). А это уже не так хорошо, если цикл большой.

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

Про дружественную функцию я не предполагал открывать функции, возвращающие константы всем подряд. Ну и сами функции, полагал, что будут храниться у класса CServerThread как private.
А вот как разделять команды - вот тут я пока думаю. Либо каждой дать идентификатор для удобства, либо (как сейчас сделано) сравнивать содержимое элемента вектора с каждой константой {if (vector_string[n].compare(Command_Login)==0) ... }. Тут, думаю, появится вопрос, а зачем тогда вектор? Да просто прежде чем сравнивать нужно бы проверить, что в буфере принято достаточно байт для команды и параметров. А это удобно сделать унифицированно.

Цитировать
Идеальный код, это такой код который не вызывает вопросов ни у Вас, ни у ваших сотрудников которые будут его сопровождать

В том и фишка, что одному нравится, другому Ад и Израиль. Smiley
Мне, например, вот такое вообще не нравится ни по оформлению строк,ни по переменным, ни по читабельности:
Код:
template<size_t len,size_t Dim, typename number_t> vec<len,number_t> proj(const vec<Dim,number_t> &v) { //проекция вектора
    vec<len,number_t> ret;
    for (size_t i=len; i--; ret[i]=v[i]);
    return ret;
}
Кстати, это фрагмент от того комментатора, которому мой код не понравился. Smiley
Ну и ему написали (с чем я согласен и не из вредности  Cheesy ): ссылка
Цитировать
Ваш трюк с циклом for мне кажется неуместным. Он хорош, когда действительно важно бежать с конца в начало, но, поскольку в ваших функциях вам все равно, то лучше использовать классический

for (size_t i=0; i<Dim; ++i)

Экономить 3 символа это, конечно, хорошо, но в отличие от классического варианта этот при прочтении прямо таки просит взять в руки бумажку и проверить, что тут нигде не налажали. Кроме того, отказ от него позволил бы вам сэкономить целый абзац в статье, раз уж вам это так нравиться.

Кроме того, вносить действие в шапку цикла считается признаком плохого стиля, а когда тело цикла пустое, рекомендуется вместо незаметной ; на той же строке, что и шапка, писать так:

for (size_t i=len; i--; ret=v) {}

или так:

for (size_t i=len; i--; ret=v)
;

Все-таки это материал для новичков, поэтому надо стремиться показывать хороший код.
« Последнее редактирование: Июля 09, 2017, 07:16:42 pm от da-nie » Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #44 : Июля 10, 2017, 09:56:40 am »

А проблемы с программами, обычно, не в понимании, что и как делает функция (это, как правило, очевидно из комментария или просто по виду функции), а в том, чтобы представить общую концепцию программы.
Скажем, вот функция:
Вот не понимая концепции её работы в рамках программы, потребуется позеленеть..

Ответе на вопрос - почему требуется зелень чтобы понять написанный код? Почему метод написан так, что сам код не объясняет решение/подход? Ведь он не делает ничего такого (никаких сложных преобразований)? Это без относительно конкретного примера - если написанный код даже не намекает читающему о используемых концепциях и заставляет читающего постоянно перескакивать между уровнями абстракции (на два вверх или на два вниз), заставляет двигать свой "стек" в голове - код плох. Особенно плох, если это ощущение не у одного читающего (в команде).
Яркий пример - глобальная переменная, которая изменяет интенсивно свое значения на разных уровнях вызова/и в разных модулях и таким же способом участвующая условных проверках. Читающему такой код будет весьма сложно помнить состояние в конкретном месте исполнения.
По конкретному примеру. Да, читается он плохо. Я могу прокомментировать - если бы у автора была нужда услышать мой комментарий, или если бы я участвовал в команде поддерживающий данный код. ИМХО - код явно требует более читаемых модификаций (и комментарии в коде тут играют второстепенную роль) начиная от того что нет нужды разделять объявления локальных переменных и их инициализацию, до того - что циклы с отрисовкой - явные кандидаты на сервис-методы

Цитировать
Ну, я тогда перефразирую, что делать слишком большие функции тоже плохо, ровно как и плодить кучу мелких по принципу, лишь бы в экран влезала каждая.
Разумеется это так. Не будем брать крайности.
Но, в свое время, там где я работаю пришли к важному правилу.
Читаемость кода - в приоритете даже над его производительностью!
Причина тому проста - гораздо проще поднять производительность в читаемом коде после, нежели фиксить ошибки или сопровождать код который нечитаемый.
Поэтому, действительно - код который не помещается (на один/два экрана) - как правило явный кандидат на переработку.

Цитировать
То есть помнить, что «Мышка бежала» получает управление через функцию «ЯичкоРазбито», которая стартует после «Снесла она яичко не простое, а золотое» в функции «ПолучениеЯичка» и перед «Не золотое, а простое» в функции «Обещание».
Еще раз - код который заставляет постоянно держать в голове разного уровня (относительно вызова) логические абстракции - так же плох, как и тот который замешивает эти уровни в единственный монолитный.



Цитировать
Честно говоря, я уже запутался в порядке предложений. Но я имею в виду вот что.
Вот это:
...
В таком случае не требуется создания класса команд. Точно также можно в пространстве имён Command задать все эти функции без класса в отдельном модуле и при первом же вызове они будут инициализированы.
Разумеется! Код был приведен в контексте раскрытия использования инициализации для глобальных-статических переменных. Всего лишь.
Все этом ожно поместить в отдельный неймспейс.
Но я предпочитаю классы. Почему? Да потому что, объект-класса можно создать более контролируемо, как и удалить. Можно так-же использовать ограничения доступа (скрыть сервисные методы) и т.д. Все что можно делать с типом - можно делать и с классом. А это недоступно в пространстве имен. Пробуйте отдать как параметр шаблона пространство имен )))

Цитировать
Но вот что ещё плохо при использовании функций, возвращающих константу: я не уверен, что цикл for (long n=0;n<constants::GetMaxItem();n++) не будет любым компилятором вызывать с каждой итерацией цикла функцию (на -o3 может и не будет). А это уже не так хорошо, если цикл большой.
Вот, все - мне нечего возразить человеку который регулярно игнорирует инициализацию выражением и на следующей строчке присваивает переменной вычисляемое значение.
Ну и так, между прочем - он вернет константную ссылку. Между прочим, метод может быть констэкспр - вычисленный на этапе компиляции. Метод может быть заинлайненый.
Вас не смущает выражение my_vector или array? Там ведь тоже идет операция смещения (указателя) и разименование его. Опять же - дляя таких целей вызовите метод, получите константную ссылку и используйте себе на здоровье.


Цитировать
Про дружественную функцию я не предполагал открывать функции, возвращающие константы всем подряд.
Внезапно, сами ответили почему класс а не пространство имен. Но, опять же - если вам нужна константа доступная только для этого класса - делайте ее членом класса (статическим). Не нравится член класса - делайте отдельный анонимный неймспейс в cpp-unite пользуемого класса (с классом для команд или без - сами решайте).

Цитировать
Либо каждой дать идентификатор для удобства, либо (как сейчас сделано) сравнивать содержимое элемента вектора с каждой константой {if (vector_string[n].compare(Command_Login)==0) ... }. Тут, думаю, появится вопрос, а зачем тогда вектор? Да просто прежде чем сравнивать нужно бы проверить, что в буфере принято достаточно байт для команды и параметров. А это удобно сделать унифицированно.

Мда.. сравнение все таки есть, но его  там.. как вы сказали?))
Цитировать
Нет, там сравнение в цикле. Для того и в вектор помещается.

Записан
Страниц: 1 2 [3] 4 5
  Печать  
 
Перейти в: