Pavel V. 0 6 февраля, 2012 Опубликовано 6 февраля, 2012 (изменено) · Жалоба Пытаюсь собрать следующий код: #include "LPC17xx.h" typedef enum { ePort0, ePort1, ePort2, ePort3, ePort4 } LPCPort; typedef enum { eHigh, eLow } LPCActive; typedef enum { eInput, eOutput } LPCDirection; template<LPCPort port, uint8_t pin, LPCActive activestate = eHigh> struct Pin; template<LPCPort port, uint8_t pin, LPCActive activestate> struct Pin { static const uint32_t mask = 1UL << pin; LPC_GPIO_TypeDef* GetPointer() { return (port == ePort0 ? LPC_GPIO0 : port == ePort1 ? LPC_GPIO1 : port == ePort2 ? LPC_GPIO2 : port == ePort3 ? LPC_GPIO3 : LPC_GPIO4); } void On() { activestate == eHigh ? GetPointer()->FIOSET = mask : GetPointer()->FIOCLR = mask; } void Off() { activestate == eHigh ? GetPointer()->FIOCLR = mask : GetPointer()->FIOSET = mask; } void Mode(LPCDirection dir) { dir == eOutput ? GetPointer()->FIODIR |= mask : GetPointer()->FIODIR &= ~mask; } uint32_t IsActive() { uint32_t ret = GetPointer()->FIOPIN & mask; if (activestate == eHigh) { return ret > 0 ? 1 : 0; } else { return ret > 0 ? 0 : 1; } } }; class IOutput { public: IOutput() { } virtual ~IOutput() { } virtual void Set(uint32_t state) = 0; virtual uint32_t Get() = 0; }; template<LPCPort port, uint8_t pin, LPCActive activestate> class Output: public Pin<port, pin, activestate> , IOutput { public: Output() { _pin.Off(); _pin.Mode(eOutput); } virtual ~Output() { } virtual void Set(uint32_t state) { state ? _pin.On() : _pin.Off(); } virtual uint32_t Get() { return _pin.IsActive(); } private: Pin<port, pin, activestate> _pin; }; Если собирать вот такой main.cpp: Pin<ePort4, 29, eHigh> g_testPin; int main(void) { while (1) { g_testPin.On(); g_testPin.Off(); } } Все ОК, выходной файл 800 байт. Но если попробовать вот такой main.cpp: Output<ePort4, 29, eHigh> g_testPin; int main(void) { while (1) { g_testPin.Set(1); g_testPin.Set(0); } } Линкер начинает ругаться: /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-abort.o): In function `abort': abort.c:(.text.abort+0xa): undefined reference to `_exit' /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-sbrkr.o): In function `_sbrk_r': sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk' /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-signalr.o): In function `_kill_r': signalr.c:(.text._kill_r+0xe): undefined reference to `_kill' /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-signalr.o): In function `_getpid_r': signalr.c:(.text._getpid_r+0x0): undefined reference to `_getpid' /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-writer.o): In function `_write_r': writer.c:(.text._write_r+0x10): undefined reference to `_write' /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-closer.o): In function `_close_r': closer.c:(.text._close_r+0xc): undefined reference to `_close' /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-fstatr.o): In function `_fstat_r': fstatr.c:(.text._fstat_r+0xe): undefined reference to `_fstat' /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-isattyr.o): In function `_isatty_r': isattyr.c:(.text._isatty_r+0xc): undefined reference to `_isatty' /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-lseekr.o): In function `_lseek_r': lseekr.c:(.text._lseek_r+0x10): undefined reference to `_lseek' /opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-readr.o): In function `_read_r': readr.c:(.text._read_r+0x10): undefined reference to `_read' collect2: error: ld returned 1 exit status make: *** [Test2.elf] Error 1 Пытался подсунуть заглушки системных функций, тогда собирается, но размер выходного файла больше 40 Кб :) Если для класса Output убрать наследование от абстрактного класса IOutput, линкер требует только функцию _sbrk, хотя тоже непонятно почему, ведь в программе нигде не используется динамическое выделение памяти.. Тулчейны пробовал разные - эффект сохраняется. Ключи компиляции и сборки: Оптимизация -O2 # GCC GCFLAGS = -O$(OPTIMIZATION) -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -Wall -Wextra --std=gnu99 -DTNKERNEL_PORT_CORTEXM3 GCFLAGS += $(patsubst %,-I%,$(INCDIRS)) -I. # G++ GPFLAGS = -O$(OPTIMIZATION) -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -Wall -Wextra -fno-rtti -fno-exceptions -DTNKERNEL_PORT_CORTEXM3 GPFLAGS += $(patsubst %,-I%,$(INCDIRS)) -I. # Assembler ASFLAGS = $(LISTING) -mcpu=cortex-m3 -mthumb -x assembler-with-cpp ASFLAGS += $(patsubst %,-I%,$(INCDIRS)) -I. # Linker LDFLAGS = -T$(LSCRIPT) -mcpu=cortex-m3 -mthumb -O$(OPTIMIZATION) -Wl,-Map=$(PROJECT).map,--cref -nostartfiles -fno-exceptions -fno-rtti -Wl,--gc-sections Что я неправильно делаю? :smile3046: Изменено 6 февраля, 2012 пользователем IgorKossak [codebox] Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
neiver 0 6 февраля, 2012 Опубликовано 6 февраля, 2012 · Жалоба Деструкторы надо выкинуть, они всё равно никогда не будут вызваны. Это инфраструктура поддержки деструкторов для глобальных объектов с виртуальными функциями такая. Эти деструкторы регестрируются с помощью функции atexit, которая тянет за собой кучу всего остального. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pavel V. 0 6 февраля, 2012 Опубликовано 6 февраля, 2012 · Жалоба Деструкторы надо выкинуть, они всё равно никогда не будут вызваны. Это инфраструктура поддержки деструкторов для глобальных объектов с виртуальными функциями такая. Эти деструкторы регестрируются с помощью функции atexit, которая тянет за собой кучу всего остального. Спасибо! Действительно, удаление деструкторов помогло :) Как все оказалось просто. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 6 февраля, 2012 Опубликовано 6 февраля, 2012 · Жалоба Это только до тех пор, пока вы не используете Get() ;) Правильное решение таково: при использовании в проекте чисто виртуальных функций надо добавить к проекту следующий файл: тынц! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alx2 0 7 февраля, 2012 Опубликовано 7 февраля, 2012 · Жалоба Если для класса Output убрать наследование от абстрактного класса IOutput, линкер требует только функцию _sbrk, хотя тоже непонятно почему, ведь в программе нигде не используется динамическое выделение памяти.. Что я неправильно делаю? :smile3046: Это Вы думаете, что не используется. :) А линкер думает иначе. Почему линкер требует тот или иной вимвол, можно узнать из map-файла. Там линер подробно указывает, какой символ из какого модуля берется и кто его затребовал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pavel V. 0 7 февраля, 2012 Опубликовано 7 февраля, 2012 · Жалоба Это только до тех пор, пока вы не используете Get() ;) Правильное решение таково: при использовании в проекте чисто виртуальных функций надо добавить к проекту следующий файл: тынц! Убрал только деструкторы и проблема исчезла. В том числе при использовании чисто виртуальных функций. Может поправили уже? Пробовал даже такой пример: int main(void) { while (1) { IOutput *pa = (IOutput *)&g_testPin; uint32_t a = pa->Get(); if(a) pa->Set(0); else pa->Set(1); } } Компилится без проблем: arm-kgp-eabi-size Test2.elf text data bss dec hex filename 956 4 264 1224 4c8 Test2.elf Это Вы думаете, что не используется. :) А линкер думает иначе. Почему линкер требует тот или иной вимвол, можно узнать из map-файла. Там линер подробно указывает, какой символ из какого модуля берется и кто его затребовал. Я, к сожалению, пока не очень в нем ориентируюсь, но невооруженным взглядом видно, что использование деструкторов в абстрактных классах тянет за собой exceptions и другую требуху, несмотря на запрещающие флаги компилятора. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 7 февраля, 2012 Опубликовано 7 февраля, 2012 · Жалоба Убрал только деструкторы и проблема исчезла. В том числе при использовании чисто виртуальных функций. Может поправили уже? Ух ты, точно! Попробовал arm-kgp-eabi-gcc 4.7.0 20110328 (experimental) - работает без sys.c. Это радует:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pavel V. 0 7 февраля, 2012 Опубликовано 7 февраля, 2012 · Жалоба Ух ты, точно! Попробовал arm-kgp-eabi-gcc 4.7.0 20110328 (experimental) - работает без sys.c. Это радует:) Тулчейн от CodeSourcery (последняя версия) тоже корректно компилирует. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
neiver 0 7 февраля, 2012 Опубликовано 7 февраля, 2012 · Жалоба Да, кстати, а зачем делать абстрактные интерфейсы типа IOutput на таком низком уровне как линии ввода вывода? Моя скромная практика показывает, что много эффективнее по размеру и скорости кода сделать класс Pin полнностью "статическим" и передавать в использующий его код в виде шаблонных параметров. А абстрактные интерфейсы с виртуальными функциями городить уже на уровне повыше. Ну, а я по случаю порекламирую свою библиотеку по работе с портами. Помимо работы с отдельными линиями там эффективно реализованна работа с произвольными группами линий. Вот так определелен класс линии ввода-вывода: https://github.com/KonstantinChizhov/Mcucpp.../mcucpp/iopin.h Порт ввода-вывода для STM32: https://github.com/KonstantinChizhov/Mcucpp...M/Stm32/ports.h Приме использования для STM32: https://github.com/KonstantinChizhov/Mcucpp..._STM32/main.cpp Сйечас у меня есть более-менее протестированные порты для AVR, MSP430 и STM32. Еще мне люди присылали свои реализации портов для LPC17xx и STM8, но я их не тестировал и в репозиторий не выкладывал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 7 февраля, 2012 Опубликовано 7 февраля, 2012 · Жалоба Еще мне люди присылали свои реализации портов для LPC17xx и STM8, но я их не тестировал и в репозиторий не выкладывал.А можно их оба мне на real at real.kiev.ua? Я потестирую :-) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pavel V. 0 7 февраля, 2012 Опубликовано 7 февраля, 2012 (изменено) · Жалоба neiver Спасибо за ссылки, буду изучать :) По коду не сразу получается воткнуть, надо будет для себя диаграммки нарисовать для наглядности. У меня GPIO в проектах в основном для "медленных" операций используются, типа управления питанием внешних модулей, поэтому накладными расходами на вызов функций работы с портами особо не заморачивался. Зато очень удобно передавать куда угодно по ссылке. Будьте добры мне тоже на почту реализацию для LPC17хх, как раз сейчас с этим процессором работаю (павел AT posten.ru). Изменено 7 февраля, 2012 пользователем IgorKossak Бездумное цитирование Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pavel V. 0 9 февраля, 2012 Опубликовано 9 февраля, 2012 · Жалоба Кстати, заметил еще одну особенность - при уровне оптимизации -O0 проблема сохраняется, тянутся системные вызовы. Начиная с -O1 перестают. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Brain13 0 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба Чтобы не плодить новые темы пишу здесь. Здравствуйте. Решил попробовать использовать полиморфизм в МК. написал такой код: // IOutDevice.h class IOutDevice { public: virtual void On(void) = 0; virtual void Off(void) = 0; }; // PC0LED.h class PC0_LED : public IOutDevice { public: PC0_LED(); virtual void On(void); virtual void Off(void); }; // PC0LED.cpp PC0_LED::PC0_LED() { } void PC0_LED::On() { GPIO_PinOutSet(gpioPortC, 0); } void PC0_LED::Off() { GPIO_PinOutClear(gpioPortC, 0); } // PC1LED.h class PC1_LED : public IOutDevice { public: PC1_LED(); virtual void On(void); virtual void Off(void); }; // PC1LED.cpp PC1_LED::PC1_LED() { } void PC1_LED::On() { GPIO_PinOutSet(gpioPortC, 1); } void PC1_LED::Off() { GPIO_PinOutClear(gpioPortC, 1); } // main.cpp int main(void) { init(); PC0_LED pc0; PC1_LED pc1; IOutDevice*dev[2]; dev[0] = &pc0; dev[1] = &pc1; while (1) { dev[0]->On(); dev[1]->On(); delay(2000000); dev[0]->Off(); dev[1]->Off(); delay(2000000); } } // Интерфейс IOutDevice, и 2 класса его реализующих для PC0 и PC1. Все время думал, что для абстрактных методов необходим rtti. И компилировал без опции -fno-rtti (размер программы 10456). В этом топике увидел, что работает и с опцией -fno-rtti, попробовал - раотает (размер программы 2228). Вопрос: почему код успешно компилируется с опцией -fno-rtti без ошибок? Разве для использования абстрактных методов не нужен rtti? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба Разве для использования абстрактных методов не нужен rtti?Нет, не нужен. Полиморфизм реализуется таблицами указателей на виртуальные функции (vtbl) для каждого класса и указателем на таблицу своего класса в каждом объекте. Имея указатель на объект вы можете найти его таблицу указателей и в ней найти указатель на нужную реализацию метода. И все, никакого мошенничества. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба Все время думал, что для абстрактных методов необходим rtti. И компилировал без опции -fno-rtti (размер программы 10456). В этом топике увидел, что работает и с опцией -fno-rtti, попробовал - раотает (размер программы 2228). Вопрос: почему код успешно компилируется с опцией -fno-rtti без ошибок? Разве для использования абстрактных методов не нужен rtti? 1. Что такое абстрактные методы? 2. RTTI - Run-Time Type Identification - определение типа на этапе выполнения. Причём тут полиморфизм, который требует просто наследования и виртуальных функций, механизм реализации которых - это таблицы указателей на функции? Для полиморфизма не требуется никакая информация о типах на этапе выполнения. RTTI потребуется, если будете использовать dynamic_cast<>. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться