Страниц: 1 2 [3]
  Печать  
Автор Тема: CppUnit порт для QNX6  (Прочитано 5957 раз)
da-nie
Full Member
***
Offline Offline

Сообщений: 217



Просмотр профиля
« Ответ #30 : Августа 13, 2018, 05:59:19 pm »

Цитировать
Она была в dos.h, которого под unix-ами нет

Логично. Smiley Просто delay находится в unistd. А "<unistd.h> содержит различные основные функции и константы POSIX". Потому я и думал, что она везде, где POSIX есть должна быть.

Цитировать
Вы, наверное, с QNX 6.6 путаете, там как раз Photon нет.

Наверное. Я дальше 6.5 не смотрел. Smiley

Цитировать
Вероятно должно. На какие-то ЕС1866 ставится. Они же разные бывают по начинке, да?

Судя по буклету, по которому заказывали, там вариативность небольшая.
Записан

И день и ночь в пути
PoP
Sr. Member
****
Offline Offline

Сообщений: 350


Просмотр профиля
« Ответ #31 : Августа 14, 2018, 02:36:50 pm »

Не всегда ведь проект делается в IDE. Да и вот свежий пример: решил-таки Linux поставить. Смотрим, что у нас есть из популярного:
Fedora
Mint
Ubuntu
OpenSuSe
Mageia
Astra Linux
Debian ?
Если не устраивает новомодная systemd - есть форк с system V.
Если не издеваться над ней подключая репозитории testing - стабильна до безобразия.
Ну а окружений рабочего стола - пактически в любом линухе на любой вкус и цвет.
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 217



Просмотр профиля
« Ответ #32 : Августа 14, 2018, 03:27:54 pm »

Не, Debian такая же, как и Ubuntu.
Я Mint поставил. Он мне понравился. Smiley
Записан

И день и ночь в пути
PoP
Sr. Member
****
Offline Offline

Сообщений: 350


Просмотр профиля
« Ответ #33 : Августа 14, 2018, 05:25:39 pm »

Видимо - Cinnamon больше похожа на XP  Smiley.
А так - всё практически тоже, только в профиль.
В основе Ubuntu - ветка unstable  Debian. Свежее общее ПО, главное - драйвера под новое железо появляются раньше. Встречаются коммерческие и не GPL программы в центре приложений. Естественно - слегка меньше стабильность.
Mint основан на Ubuntu, использует репозитории Ubuntu основные изменения - простота начальной установки и окружение по умолчанию.
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 217



Просмотр профиля
« Ответ #34 : Августа 14, 2018, 07:19:27 pm »

я поставил Mate. Smiley Меня просто достала windows 7 (я мог бы и XP поставить, но решил в качестве эксперимента всё же перейти хотя бы на семёрку). Она просто неудобная. Тупой проводник без кнопки 'на уровень выше',часто забывающий переключать папку по одинарному щелчку. Тормоза Firefox. Испорченный Paint. Нет, пора на Linux возвращаться после десятилетнего перерыва. Smiley Правда, вот чего я в линуксах не люблю, так это постоянные изменения с каждым обновлением. Я всё же люблю стабильность... Ну и система пакетов меня раньше доводила до белого каления, когда в системе половина мусора, который используют 1.5 приложения, а этот мусор тащит свои зависимости разных версий. Ставишь из тарбола программу, а ей ещё 100 пакетов надо, а им ещё, а ещё один не совместим с тем, что уже есть. Тут хоть apt работает автоматически. Вроде бы. Smiley

Цитировать
Ну а окружений рабочего стола - пактически в любом линухе на любой вкус и цвет.

Игра в конструктор меня не прельщает. Потому я и не ставил gentoo. Smiley
« Последнее редактирование: Августа 14, 2018, 07:27:54 pm от da-nie » Записан

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

Сообщений: 217



Просмотр профиля
« Ответ #35 : Октября 11, 2018, 07:08:37 pm »

Интересная штука получается.
Вот есть у меня базовый класс ошибок CErrorsBased вида:

Код:
class CErrorsBased
{
 public:  
  //конструктор
  CErrorsBased();
  //деструктор
  virtual ~CErrorsBased() {};
 protected:
  virtual void SetState(void)=0;//задать состояние в памяти
};

От этого класса унаследованы классы ошибок конкретного устройства:

Код:
class CErrorsAcs:virtual public CErrorsBased
{
 public:  
  //конструктор
  CErrorsAcs();
  //деструктор
  ~CErrorsAcs();
 public:
  void Acs_SetCANError(uint32_t index,bool state);//установить ошибку "отказ CAN"
  bool Acs_IsCANError(uint32_t index);//получить, задана ли ошибка "отказ CAN"
};
...
//----------------------------------------------------------------------------------------------------
//установить ошибку "отказ CAN"
//----------------------------------------------------------------------------------------------------
void CErrorsAcs::Acs_SetCANError(uint32_t index,bool state)
{
 cErrorsState.cAcs[index].CANError=state;
 SetState();
}
..

А от этих классов ошибок конкретного устройства унаследован общий объединяющий класс ошибок.

Код:
class CErrors:virtual public CErrorsACU,virtual public CErrorsAcs
{
 public:  
  //конструктор
  CErrors();
  //деструктор
  ~CErrors();
 public:
  void ChangeState(uint32_t index,void (CErrors::*set_function_ptr)(uint32_t,bool),bool (CErrors::*is_function_ptr)(uint32_t));//изменить состояние ошибки на противоположное
 protected:
  void SetState(void);//задать состояние в памяти
};

А вот дальше интересно. Функция ChangeState сделана так:

Код:
//----------------------------------------------------------------------------------------------------
//изменить состояние на противоположное
//----------------------------------------------------------------------------------------------------
void CErrors::ChangeState(uint32_t index,void (CErrors::*set_function_ptr)(uint32_t,bool),bool (CErrors::*is_function_ptr)(uint32_t))
{
 if ((this->*is_function_ptr)(index)==true) (this->*set_function_ptr)(index,false);
                                       else (this->*set_function_ptr)(index,true);                                      
 if ((this->*is_function_ptr)(index)==true) printf("true!\r\n");
 else printf("false!\r\n");
}

То есть, она требует два указателя на функции класса CErrors. Всё просто.
Вызываем: cErrors.ChangeState(index,&CErrors::Acs_SetCANError,&CErrors::Acs_IsCANError);

Компилятор напрягся:
Цитировать
pointer to member cast from virtual base 'CErrorsAcs'
will only work if you are very careful


Не понимаю, зачем он сделал это преобразование (а оно оказалось критичным). Эти методы унаследованы CErrors и в целом ему уже принадлежат.
Запускаем программу. И падаем. А дело в том, что функция класса CErrorsAcs вызывает SetState. Но SetState была определена в CErrorsBased и реализована в CErrors. А компилятор сделал преобразование к классу CErrorsAcs. И была вызвана функция без реализации.

Интересно, для чего компилятору понадобилось сделать такое вот преобразование?
Так-то я выбросил почти всё это наследование и сделал агрегацию, но стало интересно, почему же так получилось.

Кстати, что-то найти не могу порядок инициализации переменных (и массивов строк вида a[]="sdfdfsdf"; ) и классов и прочих сложных типов между модулями. Вот если в одном модуле класс создаётся глобально и в своём конструкторе вызывает динамическое создание другого класса, который в уже своём конструкторе желает взять строковую константу, то какие гарантии, что эта константа (определённая в том же модуле, где и конструктор её использующий) уже инициализирована? Для типа std::string - никаких, а вот для вида a[]="sdfdfsdf" есть ли гарантия, что сперва будут инициализированы все простые типы, а лишь потом сложные?. Я знаю, что порядок между модулями не определён, а внутри модуля в порядке описания (если не использовано явное указание компилятору на то, что должно был инициализировано сначала). Но тогда легко получается вышеописанная ситуация. В данном примере я заменил std:string на обычный массив и он стал инициализироваться перед инициализацией классов. В принципе, насколько я помню, секция .data как раз и хранит значения глобальных переменных, а секция .text константы. Следовательно, при запуске эти секции уже есть в программе и они уже инициализированы задолго до вызовов конструкторов любых сложных объектов.
« Последнее редактирование: Октября 13, 2018, 03:34:13 pm от da-nie » Записан

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

Сообщений: 237


Просмотр профиля
« Ответ #36 : Октября 18, 2018, 07:50:37 pm »

Цитировать
Интересная штука получается.
Вот есть у меня базовый класс ...

Вам следует почитать и изучить вопрос, как хранятся данные при виртуальном наследовании. Тут на английском но все же примерно написано, что не так просто оперировать указателями на члены класса участвующих в таком наследовании.

И вообще, резюмируя - если вы пришли к виртуальному наследованию, то с вероятностью близкой к единице вы архитектурно неправильно представляете свое решение.

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

Все это можно почитать тут
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 217



Просмотр профиля
« Ответ #37 : Октября 18, 2018, 08:23:38 pm »

Цитировать
Вам следует почитать и изучить вопрос, как хранятся данные при виртуальном наследовании. Тут на английском но все же примерно написано, что не так просто оперировать указателями на члены класса участвующих в таком наследовании.

Честно говоря, ни черта не понял, что там написано. Undecided
А так, чисто логически, непонятно, почему я не могу создать указатель на унаследованную функцию и вызвав эту функцию не получить преобразование к унаследованному классу.

Цитировать
И вообще, резюмируя - если вы пришли к виртуальному наследованию, то с вероятностью близкой к единице вы архитектурно неправильно представляете свое решение.

Это возможно. Ведь в конечном итоге я всё заменил агрегацией. Мне изначально нужно было, чтобы все классы работали с одной общей структурой и при этом совсем не хотелось передавать при инициализации ссылку на эту структуру в каждый класс, а также все функции этих классов были бы унаследованы объединяющим классом (делегирование делать плохо - этих функций сильно дофига, и я потому и разделил их на отдельные классы). Поэтому я определил структуру в базовом классе и от него унаследовал все остальные. Так как наследование было виртуальным, то базовый класс и эта структура в объединяющем классе CError находятся в единственном числе и все классы работают с одним и тем же экземпляром.

Цитировать
Все это можно почитать тут

О, спасибо!
Если я правильно понял,что там написано, гарантируется инициализация переменных до объектов.
Записан

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

Сообщений: 217



Просмотр профиля
« Ответ #38 : Октября 19, 2018, 08:16:04 am »

Нашёл занятное описание проблемы с указателями на функции классов:

Цитировать
Жуткие сведения об указателях на функции-члены

Рассмотрим ограничения, накладываемые на указатели на функции-члены. Во-первых, нельзя использовать указатель на функцию-член для статического метода. В этом случае нужно использовать обычный указатель на функцию (так что название «указатель на функцию-член» несколько некорректно, на самом деле это «указатель на нестатическую функцию-член»). Во-вторых, при работе с классами-наследниками есть несколько особенностей. Например, следующий код будет скомпилирован на MSVC, если оставить комментарии:

class SomeClass
{
  public:
    virtual void some_member_func(int k, char* p)
    {
      printf(“In SomeClass”);  
    };
}

class DerivedClass : public SomeClass
{
  public:
// Если разкомментировать следующую строку, то код в строке * будет выдавать ошибку
// virtual void void some_member_func(int k, char* p) {printf(“In DerivedClass”); };
};

int main()
{
  // Объявляем указатель на функцию-член класса SomeClass
  typedef void (SomeClass::*SomeClassMFP)(int, char *);
  SomeClassMFP my_memfunc_ptr;
my_memfunc_ptr = &DerivedClass::some_member_func; // ----- строка (*)
}

Довольно любопытно, &DerivedClass::some_member_func являтся указателем на функцию-член класса SomeClass. Это не член класса DerivedClass! Некоторые компиляторы ведут себя несколько иначе: например, Digital Mars C++ считает в данном случае, что &DerivedClass::some_member_func не определен. Но если DerivedClass переопределяет some_member_func, код не будет скомпилирован, т.к. &DerivedClass::some_member_func теперь становится указателем на функцию-член класса DerivedClass!

Приведение между указателями на функции-члены – крайне темная область. Во время стандартизации С++ было много дискуссий по поводу того, разрешено ли приводить указатели на функции-члены одного класса к указателям на функции-члены базового класса или класса-наследника, и можно ли приводить указатели на функции-члены независимых классов. К тому времени, когда комитет по стандартизации определился в этих вопросах, различные производители компиляторов уже сделали свои реализации, причем их ответы на эти вопросы различались. В соответствии со стандартом (секция 5.2.10/9), разрешено использование reinterpret_cast для хранения указателя на член одного класса внутри указателя на член независимого класса. Результат вызова функции в приведенном указателе не определен. Единственное, что можно с ним сделать - это привести его назад к классу, от которого он произошел. Я рассмотрю это далее, т.к. в этой области Стандарт имеет мало сходства с реальными компиляторами.

На некоторых компиляторах происходят ужасные вещи, даже при приведении между указателями на члены базового и наследуемого классов. При множественном наследовании использование reinterpret_cast для приведения указателя на фукнцию-член наследуемого класса к указателю на функцию-член базового класса может скомпилироваться, а может и нет, в зависимости от того в каком порядке базовые классы перечислены в объявлении наследника! Вот пример:

class Derived: public Base1, public Base2  // случай А
class Derived2: public Base2, public Base1 // случай Б
typedef void (Derived::*Derived_mfp)();
typedef void (Derived2::*Derived2_mfp)();
typedef void (Base1::*Base1mfp)();
typedef void (Base2::*Base2mfp)();
Derived_mfp x;

В случае А, static_cast<Base1mfp>(x) отработает успешно, а static_cast<Base2mfp>(x) нет. В то время как для случая Б верно противоположное. Вы можете безопасно приводить указатель на функцию член класса-наследника к указателю на функцию-член только первого базового класса! Если вы попробуете все-таки выполнить приведение не к первому базовому классу, MSVC выдаст предупреждение C4407, а Digital Mars C++ выдаст ошибку. Оба будут протестовать против использования reinterpret_cast вместо static_cast, но по разным причинам. Некоторые же компиляторы будут совершенно счастливы, вне зависимости от того, что вы делаете. Будьте осторожны!

Также в Стандарте есть другое интересное правило: можно объявлять указатель на функцию-член класса, до того как этот класс определен. У этого правила есть непредвиденные побочные эффекты, о которых я расскажу позже.

Также стоит отметить, что Стандарт С++ предоставляет указатели на члены-данные. Они имеют те же операторы и некоторые из особенностей реализации указателей на функции-члены. Они используются в некоторых реализациях stl::stable_sort, но я не знаю других значимых применениях этих указателей.


http://rsdn.org/article/cpp/fastdelegate.xml

Записан

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

Сообщений: 237


Просмотр профиля
« Ответ #39 : Октября 19, 2018, 06:29:01 pm »

Честно говоря, ни черта не понял, что там написано. Undecided
А так, чисто логически, непонятно, почему я не могу создать указатель на унаследованную функцию и вызвав эту функцию не получить преобразование к унаследованному классу.

На самом деле там две проблемы (только из-за специфики кода сразу не заметно было что когда и где вызывается - делайте что-ли упрощенные ссылки на уже компилируемый пример в том-же Coliru).
Проблема номер 1:

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

Проблема номер 2:

Как вы заметили позже дав кусок материала по "делегатам" - с виртуальными методами дело обстоит схожим способом. Они адресуются не просто смещением от адреса объекта - а еще и со смещением в зависимости от виртуальной таблицы ..

Все это компилятору не нравится (да и мне честно говоря то же). Ибо уверен что таким способо найдутся крайние случаи где нельзя точно понять какой метод вы хотите вызвать и гарантировать какой либо порядок исполнения. Поэтому компиляторы явно запрещают такое использование.

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

Цитировать
О, спасибо!
Если я правильно понял,что там написано, гарантируется инициализация переменных до объектов.

Я не понял вашего вопроса. Объекты/переменные - чем отличаются в вашем контексте? А лучше пример.
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 217



Просмотр профиля
« Ответ #40 : Октября 19, 2018, 07:29:25 pm »

Цитировать
делайте что-ли упрощенные ссылки на уже компилируемый пример

А это мысль. Cool Я как-то про такую возможность не подумал.
Вот: http://coliru.stacked-crooked.com/a/5e8e0c4f76c7cb1a Но в этой системе такое даже не компилируется (вроде бы нигде не опечатался...). Smiley

Цитировать
Все это компилятору не нравится

Тут проблема веселее, как мне кажется. Вообще, обычно принято делать поведение системы предсказуемым и ожидаемым. В данном случае компилятор себя так не ведёт. Я вполне чётко ему обозначил, что я желаю унаследовать два класса (CErrorsACU и CErrorsAcs) и чтобы каждый из них мог вызывать определённую в их суперклассе (CErrorsBased) и переопределённую в их потомке (CErrors) функцию. Для этого я указал компилятору, что желаю иметь указатель на функцию потомка CErrors. Я ожидаю, что функция, на которую сделан указатель, пусть и определена в классе CErrorsAcs, но была унаследована CErrors и отныне она принадлежит именно ему. Вроде бы достаточно понятное и простое желание. Поэтому я никак не ожидаю от компилятора перенаправления вызова этой функции в класс CErrorsAcs с последующей потерей связи с его потомком CErrors. Всё-таки, какая мне разница, что за проблемы возникают при этом у компилятора?  Angry

Цитировать
Вообще на первый взгляд - вот так кот путать пользователя передачей обработчиков методов разного уровня наследования .. в данной реализации мне показалась сомнительной.

Да там всё просто. Был класс, в котором была куча функций типа "Включить ошибку устройства ..." и "А включена ли ошибка устройства ... ?". Эти функции записывали/считывали флаги большой структуры, которая через разделяемую память передавалась процессам имитации этих устройств. Но на этапе реализации оказалось, что этих функций будет пара сотен. Не, так неудобно. Поэтому я выделил устройства в классы с их функциями и хотел чтобы все те же их функции были просто унаследованы исходным классом. Дальше встал вопрос сделать триггерную функцию "если включено, то выключить, иначе включить". Я это сделал через указатели на функции этого класса. Тут-то компилятор и возопил. Smiley

Цитировать
объекты/переменные - чем отличаются в вашем контексте?

Тем, что для объектов вызывается конструктор, а переменные просто инициализируются из секций исполняемого файла.
То есть,
char name[]="123"; - инициализируется из секции .data
CErrors cErrors; - инициализируется вызовом конструктора.

Меня интересовал вопрос, инициализируются ли классы строго после все простых типов. Судя по тому, что написано, да.
« Последнее редактирование: Октября 19, 2018, 07:52:08 pm от da-nie » Записан

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

Сообщений: 237


Просмотр профиля
« Ответ #41 : Октября 20, 2018, 03:31:59 am »

Цитировать
Тут проблема веселее, как мне кажется. Вообще, обычно принято делать поведение системы предсказуемым и ожидаемым.
А давайте посмотрим, что может значить запись :
Код:
typedef (CErrors::*set_function_ptr)(uint32_t,bool);
- это синоним set_function_ptr на указатель функции с сигнатурой (uint32_t,bool). При этом мы явно говорим, что метод должен принадлежать классу (не иметь дополнительных каких либо смещений при ссылке на метод). Вот ваш же пример - в нем добавлен не виртуальный метод doSome() в базовые классы. В мэйне вызывается конкретные методы объекта cErrors. Но нет никакой возможности вызывать непосредственно этот метод без указания типа (смещения) конкретного базового класса. Да, если методы не пересекаются по имени/сигнатуре - это очевидная ошибка компиляции отловить не получится. Но это только потому что мы явно вызываем методы и компилятор точно может определить наши намерения. В вашем случае - вы переводите все в рантайм. Компилятор не сможет различить полную сигнатуру (а именно именную сигнатуру) к каким методам будет применен вызов (на уровне  CErrors::ChangeState - это неизвестно). Он затрудняется гарантировать точные ваши намерения и принимает очевидное решение - сгенерировать ошибку компиляции. Гарантировано он может обеспечить работу только для собственных методов принадлежащих к CErrors (в примере это метод SetError)


Цитировать
Тем, что для объектов вызывается конструктор, а переменные просто инициализируются из секций исполняемого файла.
То есть,
char name[]="123"; - инициализируется из секции .data
CErrors cErrors; - инициализируется вызовом конструктора.

Меня интересовал вопрос, инициализируются ли классы строго после все простых типов. Судя по тому, что написано, да.
Нет, вы не совсем все верно поняли. В описании разделены - константная статическая инициализация и .. другие типы статической инициализации. И в вашем случае порядок инициализации будет в порядке их перечисления. "123" будет лежать где-то в .data как некий литерал, но сам name будет инициализироваться в любом случае в процессе выполнения и раньше  чем cErrors. И наличие конструктора - тут не причем.
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 217



Просмотр профиля
« Ответ #42 : Октября 20, 2018, 08:54:37 am »

Цитировать
метод должен принадлежать классу (не иметь дополнительных каких либо смещений при ссылке на метод)

Про смещения - это уже проблема компилятора, как он будет искать этот метод. Если я вставил дверь в дом, отныне ручка двери принадлежит дому точно так же, как и двери. Это уже пусть сам компилятор ищет, где там этот метод у кого лежит. И жаль, что он такого не умеет.

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

Правильно. В данном случае есть неопределённость и требуется указание, чей именно метод мы вызываем.

Цитировать
Компилятор не сможет различить полную сигнатуру (а именно именную сигнатуру) к каким методам будет применен вызов (на уровне  CErrors::ChangeState - это неизвестно). Он затрудняется гарантировать точные ваши намерения и принимает очевидное решение - сгенерировать ошибку компиляции. Гарантировано он может обеспечить работу только для собственных методов принадлежащих к CErrors (в примере это метод SetError)

Но опять-таки, это проблема компилятора. Во время выполнения он умеет работать с таблицами виртуальных функций, то есть, ничто ему не мешает так же выяснять и куда что перенаправляется.

Цитировать
И наличие конструктора - тут не причем.

Нет-нет, тут другой вопрос был. Итак, у нас есть два модуля.
В первом в *.h объявлен класс CErrors и в *.cpp написано так:

//глобальная переменная
char name[]="123";
//конструктор
CErrors::CErrors(void)
{
 printf("%s\r\n",name);
}

Во втором в *.h объявлен класс CMain и в *.cpp написано так:
//глобальная переменная
CMain cMain;
//конструктор
CMain::CMain(void)
{
 printf("CMain!\r\n");
 CErrors *cErrors_Ptr=new CErrors();
 delete(cErrors_Ptr);
}

Модули разные, поэтому порядок инициализации между ними произвольный. Пусть CMain инициализируется первым. Вопрос был в том, будет к этому моменту инициализирована переменная name или нет. Если name задать как std::string, то точно гарантий нет. А вот если задать массивом, то получается, что да.
« Последнее редактирование: Октября 20, 2018, 12:09:15 pm от da-nie » Записан

И день и ночь в пути
Страниц: 1 2 [3]
  Печать  
 
Перейти в: