Перейти к содержанию
    

Плавный переход C -> C++ под МК

42 minutes ago, Arlleex said:

Но, опять же, у Вас шаблонная функция, я бы хотел избежать этого

Избавьтесь лучше от uniun, он действительно для этой задачи не совсем уместен )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 часов назад, Arlleex сказал:

Идея ясна, спасибо.

Вот, придумался более простой вариант:

struct sendable {};
struct a : public sendable
{

};
struct b {};

inline void send_msg(sendable const & from, size_t size)
{
    auto pSrc = static_cast<void const *>(&from);
    ...............
}

template<typename T>
void send_msg(T const & data)
{
    send_msg(data, sizeof(T));
}

template<typename T, size_t items>
void send_msg(T const (& data)[items])   // если вдруг потребуется передавать массив структур
{
    send_msg(data[0], sizeof(T) * items);
}

void test()
{
    a Good = {};
    a Good2[2] = {{}, {}};
    b Bad = {};
    send_msg(Good);
    send_msg(Good2);
    send_msg(Bad);  // error: no matching function for call to 'send_msg(const b&, unsigned int)'
                    // <- note:   no known conversion for argument 1 from 'const b' to 'const sendable&'
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

57 минут назад, Сергей Борщ сказал:

Вот, придумался более простой вариант...

Вот, такой нравится вариант, он мне полностью понятен по крайней мере))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то читал я про union-ы в C++ и пришел к выводу, что в комитете дурь очень забористая.

Оказывается, нельзя в плюсах репрезентовать битовое представление, как это делалось обычно

union {
  u32   i;
  float f;
} u;

int main() {
  u.f = 3.1f;
  
  printf("%d", u.i); // undefined behavior in C++
  
  return 1;
}


И выход из ситуации через memcpy(), placement-new [] и иже им подобным костылям с трехэтажным монструозным синтаксисом.

Почему Страуструп и Ко просто не взял и не скопировал у Си?:fool:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Arlleex said:

Оказывается, нельзя в плюсах репрезентовать битовое представление, как это делалось обычно

Какой компилятор? Покажите текст ошибки при компиляции.

У меня компилятор не ругается  - ARM v6.19 в режиме C++17

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А здесь совершенно не причем, ругается или не ругается компилятор.

Он не будет ругаться, а по стандарту вышеуказанный хук слева с union-ом оборачивается UB. О как.

Компилятор у меня ARM CLang (keil-овский v6). Он, конечно, код пока что генерит правильно, однако я уже достаточно вкурил, чтобы понять, что плюсоводы такое использование union не одобряют. Одобряют только (и только лишь) хранение разных типов внутри одного кусочка памяти. Обращаться на чтение можно только к элементу, тип которого совпадает с типом элемента на последнюю запись значения в union. Это так называемая установка активного члена union-а. Совсем одурели, в америке своей.

union {
  int          i;
  float        f;
  unsigned int ui;
} u;

int main() {
  u.i             = 10;   // set 'i' member at 'active'
  unsigned int ui = u.i;  // ok (last active type - int)
  u.f             = 3.0f;
  float f         = u.f;  // ok
  int i           = u.ui; // undefined behavior
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 minutes ago, Arlleex said:

Он не будет ругаться, а по стандарту вышеуказанный хук слева с union-ом оборачивается UB. О как.

Ну это логично, данные для float и для int храняться в памяти по-разному, union позволяет обманывать компилятор, нарушая его логику. Поведение действительно непредсказуемо.

Тут напрашивается явное преобразование:

  u.f = 3.1f;
  
  auto i = static_cast<uint32_t>(u.f);
  
  printf("%d", i);

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 минут назад, Forger сказал:

Тут напрашивается явное преобразование...

Никакие касты (ни static, ни reinterpret) не влияют на UB при доступе к члену union другого типа. Это я тоже почитал((

Однако в Вашем примере static_cast выполняет немного другую роль, и, на мой взгляд, каст лишний, ибо по-умолчанию float->int произойдет автоматом с изменением представления и отбрасыванием дробной части.

В этой связи у меня более общий вопрос, но имеющий непосредственное отношение к текущей задаче: желая сэкономить память, я совместил"рабочий" байтовый буфер со структурами, по которым мне удобно обращаться к протокольным заголовкам и данным

static union uRxMsg {
  struct {
    u32 cmd,
        arg,
        crc;
  } sysInf;
  
  u8 buf[MAX_RX_MSG_SIZE];
} RxMsg;


В RxMsg.buf по байтикам пишет драйвер-разгербатор входящего потока по интерфейсу, а обработчик сообщений декодирует сообщения, обращаясь к ним по RxMsg.sysInf (и другим, если добавляются). Получается, по правилам C++ я так сделать не могу. И как тогда могу?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 minutes ago, Arlleex said:

ибо по-умолчанию float->int произойдет автоматом с изменением представления и отбрасыванием дробной части.

Да, можно без cast. Просто cast полезен для указания прогеру на потенциально скверные места

но все равно нужно делать явное преобразование.

В таком случае компилятор сам вызовет внутреннюю функцию для преобрвазования float в u32 и разместит результат во явной временной переменной, в данном случае в стеке.

 

В конце концов, если напрягает доп строчка кода , то сделайте так:

printf("%d", static_cast<uint32_t>(u.f)):

 

10 minutes ago, Arlleex said:

Никакие касты (ни static, ни reinterpret) не влияют на UB при доступе к члену union другого типа

Не влияют, но указывают начинающего с++ прогеру, что тут что-то нечисто ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 hours ago, Arlleex said:

Что-то читал я про union-ы в C++ и пришел к выводу, что в комитете дурь очень забористая.

Стандарт не описывает битовое представление int и float. Так что совершенно логично, если вы записали int, а читаете float, то стандарт не может дать никаких гарантий что именно вы прочитаете. Так что UB вполне логично. То же самое и в С, но там на это смотрят сквозь пальцы - что хотите, то и читайте 🙂

Просто в С++ сразу расписались, что при таком обращении с памятью они ничего не гарантируют.

А гарантируют только то, что если вы писали как int, то и  считать можете как int.

В С++ есть UB, которые могут показаться гораздо более странными. Например переполнение при инкременте знакового целого - UB.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, Arlleex said:

Получается, по правилам C++ я так сделать не могу.

Можно, почему же нет ))

У вас там только беззнаковые целые числа. UB возможно лишь в вашем коде, не в коде встроенных библиотек. А это отслеживается и отлаживается.

Безусловно нужно заботится о правильном заполнении данными buf[MAX_RX_MSG_SIZE] , чтобы при разборе через sysInf не вылезли неприятности. Но компилятор не может об этом знать, поэтому никак это не запрещает.

К слову, я сам подобным образом делал и продолжаю делать. Но такие "фишки" лучше тщательно отлаживать/тестировать и прятать глубоко в коде, чтобы "наружу" не вылезло. Это не только к плюсам относится, это вообще )

 

зы Вообще, C++ заметно более строгий чем С. Эта потребность возникла не на ровном месте по прихоти группки людей. Это как ПДД - каждый пункт которых написан кровью. Тут что-то подобное, но не такое кровожадное ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 часов назад, xvr сказал:

В С++ есть UB, которые могут показаться гораздо более странными. Например переполнение при инкременте знакового целого - UB.

Как раз переполнение знаковых с соответствующим UB - это не присущая C++ особенность. В Си тоже переполение знакового - UB. И этот UB весьма обоснован.

Цитата

Просто в С++ сразу расписались, что при таком обращении с памятью они ничего не гарантируют.

Понимаете ли, в чем основная соль. Соль в том, что при оптимизациях с потенциальным UB могут выкидываться целые куски кода, как будто их и не было, либо компилятор может генерить полную дичь. Я бы понял, если в случаях с union-ами сделали поведение, определяемое реализацией. Я бы проверил на своем компиляторе и забыл. А сейчас получается, что я тупо не могу написать оптимизированный по объему RAM и скорости выполнения код! Видете ли, гуру со стековерфлоу, ссылаясь на параграфы из стандарта C++, приходят к примерно одному мнению - чтобы наложить структуру на буфер (я про подход, где гарантированно не будет проблем с активизацией членов union и strict aliasing), надо *боже дай мне сил не материться* скопировать этот буфер в объект такой структуры. А если я плюю на все это и пишу в union буфер и структуру (как показывал выше в коде), то это потенциальный UB и при сборках/пересборках результат может быть совершенно разным - как карта ляжет.

А глядя вкупе на тот ворох метафигни, которую сейчас в современные плюсы добавили у меня возникает закономерный вопрос: получается, C++ больше развивают в сторону каких-то питонов с рубами, чем в сторону языков, на которых по-прежнему можно писать эффективный код для любой архитектуры. Я как ни сяду писать что-то на плюсах (потому что есть у него кое-что такое, чего нет в Си), вечно упираюсь лбом в какую-то наитупейшую мелочь, которая, как мне казалось, давным давно должна была быть разрулена.

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

7 часов назад, Forger сказал:

У вас там только беззнаковые целые числа. UB возможно лишь в вашем коде, не в коде встроенных библиотек. А это отслеживается и отлаживается.

Это для примера я беззнаковые привел. А по факту в структурах лежит черти что и что там будет лежать через пару итераций доработок ПО мне не ведомо. Я лишь атрибутами выравнивания/размещения гарантирую корректность расположения структур, наличие padding-а и т.д. для безопасной работы с выровненными данными на Cortex-M0, не умеющим невыровненный доступ.

Цитата

Эта потребность возникла не на ровном месте по прихоти группки людей. Это как ПДД - каждый пункт которых написан кровью. Тут что-то подобное, но не такое кровожадное ))

Открывая стандарт, я не вижу ту самую кровь, там не пишут, почему та или иная штука приводит к UB. Там просто констатируется факт - а уж сообщество дальше додумывает, почему так. И это печально.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

51 minutes ago, Arlleex said:

Открывая стандарт, я не вижу ту самую кровь, там не пишут, почему та или иная штука приводит к UB.

В ПДД тоже нет ничего про кровь ))

 

59 minutes ago, Arlleex said:

А глядя вкупе на тот ворох метафигни,

Никаких таких проблем с переходом с С на плюсы у меня лично не было. Как применял union и другие чисто сишные штуки для подобных целей так и применяю. 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Arlleex сказал:

приходят к примерно одному мнению - чтобы наложить структуру на буфер (я про подход, где гарантированно не будет проблем с активизацией членов union и strict aliasing), надо *боже дай мне сил не материться* скопировать этот буфер в объект такой структуры

Есть еще вариант с placement new().

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А placement new отменяет все компиляторные хотелки относительно strict aliasing? Т.е. не будет ли это по-прежнему UB?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...