Например TDA7294

Форум РадиоКот :: Просмотр темы - Проблема макросов в классах.
Форум РадиоКот
https://radiokot.ru/forum/

Проблема макросов в классах.
https://radiokot.ru/forum/viewtopic.php?f=57&t=111109
Страница 1 из 2

Автор:  Pink-Pank [ Чт дек 18, 2014 08:42:24 ]
Заголовок сообщения:  Проблема макросов в классах.

Всем добрый день!

Частенько использую макросы для автоматизированного расчета загружаемых в регистры значений. Например:
Код:
#define F_CPU 1200000UL
#define TIMER_FREQUENCY_HZ   1013   // Частота срабатывания таймера в герцах.
#define LOAD_VALUE   ((unsigned char)( round(((double)F_CPU / (double)TIMER_FREQUENCY_HZ / 8 - 1))))
....

OCR0 = LOAD_VALUE;   // 8 - предделитель таймера. Режим CTC


В общем, если использую подобные макросы при работе с регистрами напрямую или передавая значение функции, то все ОК.
А на этот раз решил поиграться с классами. Создал класс и появилась проблемка. При передаче функции класса числового значения все ОК. Либо если передаю макрос, где нет приведения типов, то тоже все ОК. А вот если в макросе есть приведение типа переменной, то компилятор начинает материться, что:
missing binary operator before token "("
Кто может сталкивался с такой проблемой? Как ее решить? Я так предполагаю, что препроцессор сначала подставляет выражение из макроса, а уже потом его рассчитывает. Может можно как-то заставить его сначала рассчитать это значение, а потом уже подставлять куда надо? Или как-то альтернативно решить эту проблему?
Какой ентому гаду бинарный оператор нужен?

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

Автор:  ploop [ Чт дек 18, 2014 09:34:27 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

У вас точка с запятой в макросе.
Pink-Pank писал(а):
Я так предполагаю, что препроцессор сначала подставляет выражение из макроса, а уже потом его рассчитывает

Именно так.
Pink-Pank писал(а):
Если я функции класса передаю не переменные, а числовые константы, можно как-то компилятор заставить, чтобы функция не принимала значения через стек (или регистры), а генерировалась инлайном с подстановкой нужных значений, не качая их из стека?

Нет. Функция есть функция, это машинный код в итоге. Препроцессор не сможет запустить её на исполнение в результате компиляции и оставить только результат, так как неизвестно, что там внутри функции вы наворотили.
Ой, кажется не так вас понял
И, кстати, что за классы вы используете? У вас C++?
Цитата:
то с учетом того, что она в классе и простой инлайн не катит, но вызывается при этом всего один раз.

С чего это не может быть инлайновых методов? Вполне могут.

Автор:  Pink-Pank [ Чт дек 18, 2014 09:54:36 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

В макросе у меня нет точек с запятой. Это я просто здесь "намешал" код и макросы. Щас поправлю.
Да, я в студии 6 на си ++ изголяюсь. Хотя можно было бы все проще оформить - просто для опыта решил через класс.
Цитата:
С чего это не может быть инлайновых методов? Вполне могут.

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

Автор:  ploop [ Чт дек 18, 2014 10:10:36 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Думаю, вы что-то намутили...
Во-первых давайте не будем называть "функции класса", они называются методы, иначе рвёт мозг.
Pink-Pank писал(а):
Ведь если сделать два разных объявления классов с одинаковым набором внутренних переменных, потом создать эти два класса и попытаться присвоить значения одного класса другому, то компиль также выдаст ошибку. Думаю, здесь что-то подобное..

Как вы это делаете? Ничего не понял, покажите пример.

Автор:  Pink-Pank [ Чт дек 18, 2014 10:17:32 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Методы.. Шметоды.. Это все условности! ))) Главное - полет мысли! ))))))
Но если Вам так привычнее - пожалуйста! Мне не трудно. )

Код:
class First {
   int memi;
   double memd;
};

class Second {
   int memi;
   double memd;
};

class First obj1;
Second obj2 = obj1;   // ошибка: obj1 и obj2 имеют разные типы


Да и как я мог намутить, если передача обычного числа, макроса или переменной прокатывает, а макрос с преобразованием типов вызывает ошибку?
Т.е. если я передаю выражение, скажем F_CPU/16, то все ок. А если выражение (uint16_t)((double)F_CPU/16), то получается облом... Хотя при передаче в простую функцию второе выражение норм работает.

Автор:  ploop [ Чт дек 18, 2014 10:46:29 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Pink-Pank писал(а):
 // ошибка: obj1 и obj2 имеют разные типы

Естественно! Первый имеет тип First, второй - Second. А если они внутри одинаковы - так это ваша проблема, так как такой подход рвёт все шаблоны ООП.
Pink-Pank писал(а):
А если выражение (uint16_t)((double)F_CPU/16), то получается облом...

Ошибка то хоть какая?

Автор:  Pink-Pank [ Чт дек 18, 2014 10:52:31 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

я ж писал
missing binary operator before token "("

Автор:  Siarzhuk [ Чт дек 18, 2014 11:28:52 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Pink-Pank писал(а):
А вот если в макросе есть приведение типа переменной, то компилятор начинает материться, что:
missing binary operator before token "("
Кто может сталкивался с такой проблемой? Как ее решить? Я так предполагаю, что препроцессор сначала подставляет выражение из макроса, а уже потом его рассчитывает.


С какой проблемой? Где кот с классами? Телепатам гадать не на чем. ;-) На то он и называется ПРЕпроцессором, что он занимается ПРЕпроцессингом - т.е. работает с ко́дом ещё до компиляции.

При непонятных проблемах с макросами нужно включать опцию

-F Preprocess only

результат работы препроцессора будет сохранен в файле с расширением *.i а компиляция не будет производиться. При нормальной компиляции этот вот *.i и скармливается компилятору. Обычно достаточно одного взгляда на развёрнутый макрос чтобы понять в чём проблема.

Для inline попробуйте определить тело функции прямо v определении класса в h файле. А вообще нужно читать мануал на компилятор соответствующую тему - там наверняка оговариваются нюансы использования.

Pink-Pank писал(а):
Да и как я мог намутить,


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

Pink-Pank писал(а):
// ошибка: obj1 и obj2 имеют разные типы


Определите операторы присваивания и будет вам счастье. Это нужно делать даже для одинаковых типов если они имеют ссылки на внешние ресурсы - по умолчанию компилятор создает оператор присваивания с простым копированием данных если оператор=(...) для этого типа не задан прокладкой между стулом и клавиатурой.

Автор:  Pink-Pank [ Чт дек 18, 2014 11:51:51 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Цитата:
Для inline попробуйте определить тело функции прямо v определении класса в h файле. А вообще нужно читать мануал на компилятор соответствующую тему - там наверняка оговариваются нюансы использования.

Уже пробовал.. Не помогает..
Цитата:
С какой проблемой? Где кот с классами?

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

поподробнее можно? Что-то я не очень понял, о чем Вы? Вы про перегрузку операторов?
Цитата:
-F Preprocess only

не -F, а -E
Сейчас попробую.
Что-то не генерится этот файл..
Выдает ошибку ld returned 1 exit status collect2.exe 0 0

Автор:  Siarzhuk [ Чт дек 18, 2014 12:13:54 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Pink-Pank писал(а):
Цитата:
С какой проблемой? Где кот с классами?

Да что Вам мой кот, если компилятор глотает обычные числовые значения и макросы без преобразования типов.


А без кота разговор беспредметен. Ну глотает, и чо? А вот нужные вам макросы не глотает. Не переваривает стало-быть их. Несъедобно готовите раз котейко давится. Скобок туда по уму добавьте - сожрёць как миленький - и не такое сжирал. И ещё раз про *.i выхлоп напоминаю - дюже важный доку́мент для пущего понимания процессов "прокладкой".

Автор:  Siarzhuk [ Чт дек 18, 2014 12:22:04 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Pink-Pank писал(а):
Вы про перегрузку операторов?


да, они, что-то типа

Код:
Second* Second::operator=(const First& first) {
  // тут присвоЯем поля
  return *this;
}


Pink-Pank писал(а):
Цитата:
-F Preprocess only

не -F, а -E
Сейчас попробую.
Что-то не генерится этот файл..
Выдает ошибку ld returned 1 exit status collect2.exe 0 0


Ну может и не -F и не *.i - вам на месте виднее - гляньте в папках где временные файлы/результаты компиляции - может какие *.pre или что-то в этом роде сохраняется - а сообщение означает что линкер не нашёл чего хотел - т.е. как-бы понятно почему - объектников-то ведь нету - один препроцессор. удачи.

Автор:  Pink-Pank [ Чт дек 18, 2014 12:25:57 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Цитата:
Несъедобно готовите раз котейко давится. Скобок туда по уму добавьте - сожрёць как миленький - и не такое сжирал.

Видно, скобочками и давится - потому что у меня их как раз валом! :)))

А как Вам тот факт, что тот же макрос обычной функцией принимается без проблем? ;)

Вот Вам мой класс *.h
Спойлер
Код:
#ifndef __Usart_H__
#define __Usart_H__

#include <avr\io.h>

#define INLINE      inline __attribute__((__always_inline__))
#define NOINLINE   __attribute__((__noinline__))

typedef enum
{
   UART      =   (0 << UMSEL),      // Режим работы UART
   USART      =   (1 << UMSEL)      // Режим работы USART
} Work_regim_Def;

typedef enum
{
   _5_bit      =   0,               // Ширина посылки 5 бит
   _6_bit      =   1,               // Ширина посылки 6 бит
   _7_bit      =   2,               // Ширина посылки 7 бит
   _8_bit      =   3,               // Ширина посылки 8 бит
   _9_bit      =   0b111            // Ширина посылки 9 бит
} Character_Size_Def;

typedef enum
{
   No_Par      =   (0 << UPM0),      // Нет бита четности
   Even      =   (0b10 << UPM0),      // Дополнение до четного
   Odd         =   (0b11 << UPM0)      // Дополнение до нечетного
} Parity_Mode_Def;

typedef enum
{
   _1_stop      =   (0 << USBS),      // 1 стоп-бит
   _2_stop      =   (1 << USBS)         // 2 стоп-бита
} Stop_Bit_Def;

typedef enum
{
   T_Rising   =   (0 << UCPOL),      // В синхроннном режиме выдача данных по нарастающему фронту
   T_Falling   =   (1 << UCPOL),      // В синхронном режиме выдача данных по спадающему фронту
   R_Rising   =   T_Falling,
   R_Falling   =   T_Rising
} Polarity_Def;

typedef enum
{
   Normal      =   (0 << U2X),         // нормальная скорость передачи
   Double      =   (1 << U2X)         // Двойная скорость передачи
} Double_Speed_Def;

typedef enum
{
   Alone      =   (0 << MPCM),      // Режим точка-точка
   Multi      =   (1 << MPCM)         // Мультипроцессорный режим
} Multiproc_Def;

class Usart
{
//variables
public:

protected:
private:

//functions
public:
   Usart();
   ~Usart();
   void Init  (uint16_t            Baud_rate      =   2400U,
            Work_regim_Def         Work_regim      =   UART,
            Character_Size_Def      Character_Size   =   _8_bit,
            Parity_Mode_Def         Parity_Mode      =   No_Par,
            Stop_Bit_Def         Stop_Bit      =   _1_stop,
            Polarity_Def         Polarity      =   T_Rising,
            Double_Speed_Def      Double_Speed   =   Normal,
            Multiproc_Def         Multiproc      =   Alone);
protected:
private:


}; //USART



#endif //__USART_H__


Вот мой класс *.cpp

Спойлер
Код:
#include "Usart.h"
#include <avr\io.h>



// default constructor
Usart::Usart()
{
} //USART

// default destructor
Usart::~Usart()
{
} //~USART



void Usart::Init   (uint16_t            Baud_rate,
               Work_regim_Def         Work_regim,
               Character_Size_Def      Character_Size,
               Parity_Mode_Def         Parity_Mode,
               Stop_Bit_Def         Stop_Bit,
               Polarity_Def         Polarity,
               Double_Speed_Def      Double_Speed,
               Multiproc_Def         Multiproc)
{

      
      UBRRL = Baud_rate;   
}


Вот моя функция с вызовом и подстановкой макроса:

Спойлер
Код:
#define F_CPU 1200000UL

#include <avr\io.h>
#include <util\delay.h>                                 
#include <avr\interrupt.h>
//#include <math.h>
#include "Pins.h"
#include "Usart.h" // мой класс


#define BOAD_RATE 500

// Если синхронный режим
//#define UBRR (uint16_t)((round((double)F_CPU/2.0/BOAD_RATE))-1)
// Асинхронный с включенным удвоением скорости
//#define UBRR (uint16_t)((round((double)F_CPU/8.0/BOAD_RATE))-1)
// Асинхронный с нормальной скоростью
#define UBRR (uint16_t)((round((double)F_CPU/16.0/BOAD_RATE))-1)

//#define UBRR   (500)
//#define UBRR   (F_CPU/16)

class Usart uart;

__attribute__((OS_main)) int main(void)
{   
   uart.Init(UBRR, UART, _8_bit);     
}

Автор:  Siarzhuk [ Чт дек 18, 2014 12:36:37 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Pink-Pank писал(а):
Цитата:
Несъедобно готовите раз котейко давится. Скобок туда по уму добавьте - сожрёць как миленький - и не такое сжирал.

Видно, как раз скобочками и давится - потому что у меня их как раз валом! :)))

А как Вам тот факт, что тот же макрос обычной функцией принимается без проблем? ;)


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

Автор:  ploop [ Чт дек 18, 2014 14:02:46 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

У вас проблема точно в макросе? Раз ругается на битовую операцию, значит может быть в структуре Work_regim_Def, что после него идёт? Вы кажется намутили с областью видимости индентификатора UART

Автор:  Pink-Pank [ Чт дек 18, 2014 14:42:32 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

то, что идет после никакого отношения к ошибке не имеет. Я те параметры пробовал и вовсе комментировать, оставлял только один, который не робит. Не помогло. Перечисления я там сделал, чтобы вводимые значения в качестве параметров были фиксированными. Чтобы пользователь класса не мог запулить туда что-то не удобоваримое.

Да и при нажатии на ошибку выкидывает именно на макрос.

Попробую в IAR загнать.. если схавает - значит студия ка-ка. Если нет и с такой же ошибкой - значит ка-ка я! :)))

Автор:  Siarzhuk [ Чт дек 18, 2014 17:07:33 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Pink-Pank писал(а):
Код:
//#include <math.h>



А функция round точно видна и не перекрывается переменной с таким именем?

Да и %s/BOAD/BAUD/g надо бы сделать. :-)

Автор:  Pink-Pank [ Пт дек 19, 2014 07:33:56 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Видна. У меня нет таких переменных.

Автор:  Аlex [ Пт дек 19, 2014 07:57:40 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

А если её (round) для пробы выкинуть из макроса, проглотит ?
ИМХО, для начала нужно методом исключения узнать, что конкретно "мешается" в макросе, а потом уже думать почему так происходит.

Автор:  Siarzhuk [ Пт дек 19, 2014 10:55:49 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Pink-Pank писал(а):
Видна. У меня нет таких переменных.


Т.е. если написать пару строками раньше что-то типа

double d = round(2342.346456);

компилятор скушает и не ругнётся?

ну разбивайте макрос по операциям на разных строчках с промежуточными результатами и смотрите на какой чертыхнётся если лень выхлоп препроцессора искать и времени не жалко.

В порядке постукивания по бубну оберните всю подстановку в скобки. Или воспользуйтесь конструкторо-подобной нотацией оператора приведения:

Код:
#define UBRR uint16_t( round( double(F_CPU) / 16.0 / BOAD_RATE ) - 1)

Автор:  BCluster [ Пт дек 19, 2014 12:37:19 ]
Заголовок сообщения:  Re: Проблема макросов в классах.

Проверил в IAR ARM такую конструкцию, она работает

Страница 1 из 2 Часовой пояс: UTC + 3 часа
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/