Open apolukhin opened 3 years ago
yndx-antoshkka, 12 июля 2017, 12:04 А такой вариант вас устроит:
template <uinptr_t A, class T>
struct dma: std::reference_wrapper<T> {
dma() noexcept
: std::reference_wrapper<T>{ *reinterpret_cast<T*>(A) }
{}
template <class U>
explicit dma(U&& u) noexcept(is_nothrow_assignable_v<T, U>)
: std::reference_wrapper<T>{ *reinterpret_cast<T*>(A) }
{
*this = std::forward<U>(u);
}
};
// Usage:
dma<405338, std::uint32_t> var;
dma<40583, std::uint32_t> var = 100;
Бонусом можно будет навешать static_assert на alignment и платформо специфичные допустимые диапазоны адресов.
avraliov.andrey, 12 июля 2017, 15:25 yndx-antoshkka, Спасибо за ответ. Да это вариант, сам пользую подобные вещи. Это можно запихать в либу. Но! количество кода с читаемостью и последующим сопровождением на лицо. Страуструп на Cppcon2016 сам сказал что нужен компромисс между фичами в языки и библиотеках. Одни дают экспрессивность языка, другие время компиляции. Мне кажется что мой любимый С++ (как один из основных языков в этом программирования железа) ДОЛЖЕН делать это просто и дубово, с проверкой типа, что это не просто int, а адрес на уровне языка. Развитие темы мне кажется это так же как ada - простой синтаксис для битовых полей указанной переменной (насколько я зная битоые поля в c++ оставлены на откуп разработчика компилятора.). в ada: for var at 0 range 0 .. 3; что означает в переменной var в нулевом байте использовать только первые четыре бита. Все с гарантией от стандарта на уровне языка.
Как это будет выглядеть на С++ мы с вами представляем!!! Разница есть
yndx-antoshkka, 12 июля 2017, 15:43 avraliov.andrey, предлагаю продумать следующую идею:
"Набор функций и классов, полезных для embedded разработки."
Давайте соберём побольше полезных классов/конструкций языка и напишем proposal сразу на добавление их всех. Если есть уже готовая популярная библиотека - дайте на неё ссылку, задача упростится :)
avraliov.andrey, 12 июля 2017, 16:43 yndx-antoshkka, Библиотек таких не видел. Много embedded кода вежде на обычном С. Энтузиасты С++ выкручиваются сами способами типа вашего. Лично я пока не вижу способа решить проблему без дополнения именно синтаксиса языка, но я программист любитель (по профессии я врач), до уровня Антона Полухина мне не угнаться. Но если вы с высоты своего опыта видите что это реально сделать имеющимися средствами хотя бы С++17, то скажите. Я буду думать, искать и пробовать. И на какой площадке обсуждать, куда присылать?
yndx-antoshkka, 12 июля 2017, 17:16 avraliov.andrey, обсуждать стоит здесь, присылать сюда же :)
У меня нет особого опыта в embedded разработке, я не знаю типичных задач и проблем embedded разработчика. Так что нужен человек, который будет активно жаловаться на что, чего ему не хватает в C++
avraliov.andrey, 12 июля 2017, 18:08 yndx-antoshkka, Ну мне после приобретенного опыта в ada программировании стало очевидно, что в С++ нужен способ удобного и гарантированного назначения адреса переменным, удобная и гарантированная работа с битовыми полями. что бы можно было написать:
typename enable_t;
for enable using size 1; //(bit)
typename reset_t;
for reset using size 1; //(bits)
typename data_t;
for data using size 8; //(bits)
struct status_register
{
enable_t en;
reset_t res;
data_t data;
};
for status_register using size 16;
for status_register using address 34657678;
for status_register.en using range 0..1;
for status_register.reset using range 1..2;
for status_register.data using range 8..15;
На выходе получаем регистр с адресом и использьванием только нужных битов: 1100000011111111 по адресу ххх.
Читаемость и программируемость как мне кажется на высоте.
Если битовые операции делать через |= &= ~=, то мне кажется это уже не с++ а галимый С, от которого мы вроде пытаемся уйти в сторону типобезопастности , читаемости, выразительности...
yndx-antoshkka, 13 июля 2017, 17:08 avraliov.andrey, Да, c полями битов в стандарте так себе:
[class.bit] Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined.
Надо подумать, как это исправить, ничего не разломав. По идее нужен специальный синтаксис, который говорит что биты идут строго в том порядке, что написали
avraliov.andrey, 17 июля 2017, 9:46 yndx-antoshkka, абсолютно с вами согласен!!!
avraliov.andrey, 23 июля 2017, 20:15 yndx-antoshkka, нашел в инете интересное решение. Не то что хотелось бы в идеале но тем не менее.
#include <type_traits>
#include <cstddef>
#include <cstdint>
template <std::size_t LastBit>
struct MinimumTypeHelper {
typedef
typename std::conditional<LastBit == 0 , void,
typename std::conditional<LastBit <= 8 , std::uint8_t,
typename std::conditional<LastBit <= 16, std::uint16_t,
typename std::conditional<LastBit <= 32, std::uint32_t,
typename std::conditional<LastBit <= 64, std::uint64_t,
void>::type>::type>::type>::type>::type type;
};
template <size_t Index, size_t Bits = 1>
class BitField {
private:
enum {
Mask = (1u << Bits) - 1u
};
typedef typename MinimumTypeHelper<Index + Bits>::type T;
public:
template <class T2>
BitField &operator=(T2 value) {
value_ = (value_ & ~(Mask << Index)) | ((value & Mask) << Index);
return *this;
}
operator T() const { return (value_ >> Index) & Mask; }
explicit operator bool() const { return value_ & (Mask << Index); }
BitField &operator++() { return *this = *this + 1; }
T operator++(int) { T r = *this; ++*this; return r; }
BitField &operator--() { return *this = *this - 1; }
T operator--(int) { T r = *this; --*this; return r; }
private:
T value_;
};
template <size_t Index>
class BitField<Index, 1> {
private:
enum {
Bits = 1,
Mask = 0x01
};
typedef typename MinimumTypeHelper<Index + Bits>::type T;
public:
BitField &operator=(bool value) {
value_ = (value_ & ~(Mask << Index)) | (value << Index);
return *this;
}
explicit operator bool() const { return value_ & (Mask << Index); }
private:
T value_;
};
union reg
{
std::uint32_t raw;
BitField<0,1> en;
BitField<1,1> rst;
BitField<5,3> data;
};
int main()
{
reg my_reg;
my_reg.data = 4;
return 0;
}
Перенос предложения: голоса +3, -7 Автор идеи: avraliov.andrey
Изучая язык Ada захотелось такую же, человеческую возможность использовать читаемый и дубовый способ назначения адресного пространства идентификаторам. Без всяких reinterpret_cast. Очень не хватает в программировании embedded приложений.
В ada:
Хотелось бы в С++ что то в этом роде:
Да, понимаю что нужно добавить новое ключевое слово в язык. Может кто предложит идею в более простой реализации. Только, думаю не стоит говорить что reinterpret_cast<>()... это вполне замечательный вариант. Да он работает, но читаемость кода заметно ухудшается со всеми вытекающими.