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

Arlleex

Свой
  • Постов

    5 816
  • Зарегистрирован

  • Посещение

  • Победитель дней

    14

Arlleex стал победителем дня 6 апреля

Arlleex имел наиболее популярный контент!

Репутация

131 Очень хороший

2 Подписчика

Информация о Arlleex

  • Звание
    Гуру
    Гуру

Контакты

  • ICQ
    Array

Посетители профиля

18 034 просмотра профиля
  1. Без разницы что они там вызывают. Факт есть факт - new, delete - такие же нативные операции среди ключевых слов языка, как и всякие там sizeof. Не нужно отрицать очевидное. Иначе в плюсах могли тупо оставить вызовы маллока функциями, как в си.
  2. Наследование в C++ прилеплено только лишь и потому, что язык преследует ООП-парадигму. Без наследования была бы не возможна концепция позднего связывания. И да - без наследования - легко. В Си не было никаких наследований и там не возникало вопросов "как без него". Для толстых проектов типа каких-то CAD-ов, геймдева и т.д. это вполне может пригодиться, соглашусь. Не так. В плюсах ключевые слова new и delete зарезервированы как раз для управления динамическим выделением памяти. В Си вызывали malloc/free - а это функции. Самые обыкновенные. Так что да - в плюсах вполне однозначно изначально был заложен механизм работы с динамической памятью на уровне синтаксиса операций.
  3. Был (есть) в отпуске, но, пожалуй, скажу пару слов. Надежды, возлагаемые на C++ в части облегчения исходников, улучшения их сопровождения и в целом удобства разработки ПО - не оправдались. Этак, процентов на 90. Но это не значит, что я не буду писать на нем. Когда переходил с Си, основная болезненная для меня тема, а именно - сокрытие данных и более строгая изолированность модулей за счет применения классов и пространств имен - покрыта возможностями C++ на 100%. Наверное, это единственное, чего мне так сильно не хватало в Си. Будь в Си хотя бы пространства имен, как в плюсах, я, наверное, вряд ли бы переходил. Во всем остальном C++ весьма переусложнен и витиеват, особенно для ембеддед. Тучный и порою нечитаемый синтаксис, в котором приходится ковыряться, напрягая мозг и отвлекаясь от основной цели. Десять и больше способов сделать ровно одно и то же (например, инициализация объектов или переменных). Туманные перспективы писать действительно переносимый код - "фишки" последних редакций стандартов выглядят такими, что создается впечатление о их выпиливании уже в следующей редакции. Говнокод и нормальный код выглядят примерно одинаково - но это следствие первых двух факторов. Излишняя универсальность, при этом эта универсальность практически всегда смотрит "не туда" - C++ заставляет думать в неких заранее определенных категориях, поэтому шаг влево и идеальная структура твоего кода рушится. Стандартная библиотека, которая всегда хорошо выглядит лишь на учебных и удобных примерах, или в качестве вполне рабочих примеров-псевдокодов для объяснения на разных форумах - а в реальных проектах (и тем более для эмбеддед) многое из стандартной библиотеки реализуется по-своему. Очень странное желание комитета (вернее, той группы энтузиастов, что пилят очередную версию стандарта) объединить все области в одном месте - и принципы ООП, и какие-то уже вполне конкретные алгоритмы, и даже механизмы обеспечения многозадачности - стандартная библиотека уже давно обрастает трэд-сэфити конструкциями, которые упрощают (наверное) порог входа в многопоточное кодирование, но на мой взгляд такой подход потом заставит родить еще 100500 методов отлова ошибок юзеров, которые окончательно запутаются в назначении всех этих премудростей и начнут жоско говнокодить, лишь бы работало как-нибудь. Чего дальше ожидать? Собственные стеки протоколов? Судя по развитию языка - ожидать. Пишу ли я на C++? Ну, как сказать. Весь нижний уровень драйверов я пишу в стиле Си - заимствую по ситуации из плюсов вкусовщину - крайне стабильные в поведении вещи - нэймспейсы, классы, несложные шаблоны и перегрузки. Саму логику работы могу описывать в ООП-стиле, а могу не описывать. Честно говоря, какими бы сложными не были мои девайсы, применение абстракций и ООП-парадигмы в финальном варианте выглядит как "применил ООП ради ООП", а не ради упрощения читаемости и понимаемости кода. Лучше делать упор на "базу" - писать потокобезопасно, без гонок, без сомнительной универсальности, которая с вероятностью 99% не выстрелит, с адекватным пользованием ресурсов, с предположением, что тебе же этот код и сопровождать потом и главное - с твердым пониманием происходящего. А то, что я не пользуюсь огромным количеством встроенных в C++ премудростей - да и фиг с ними. Этих премудростей привносят в очередной редакции стандарта как г*на на лопате - и вуаля - твой код теперь пахнет дурно, потому что, видите ли, новый стандрат добавил в стандартную библиотеку то-то сё-то, а в твоем коде это "то-то" было впилено собственноручно.
  4. Нет, с точки зрения аппаратной реализации мне как раз понятно все. Я говорил об историческом наследии именно в программном обеспечении, реализующим всякие ширпотребные протоколы.
  5. Можете наглядно показать, что Вы имели в виду? Ибо я читаю это как попытаться запихнуть структуру с FAM в другую структуру, и дописать за ней CRC. Но любые попытки сделать так тщетны, т.к. нельзя использовать FAM-структуры как член другой структуры.
  6. Вы правы, косяк в этом есть. До какого-то момента писал так - вот и попал кусок сюда в том виде в каком есть. Но на самом деле сколько своего писал, сколько чужого лопатил - пока что ни разу не удалось нарваться на конфликт дефайнов)) Возможно, потому, что в моих исходниках мало подключений сторонних библиотек. А те, что подключаются, не пересекаются названиями.
  7. Ды кто его теперь знает. Исторически в конец всегда запихивал. А сейчас понимаю, что с точки зрения языка программирования это очень выходит костыльно.
  8. Из крайнего проекта (извернулся трюком с union, но это все равно громоздко и муторно): // это с компа надо отправить в железку, а та отправит в свой RS-485 len байт struct sTxMsgRS485SendCmd { sMsgHdr hdr; eMsgUID uid; u32 ifNum; u32 len; union { u8 byte[MAX_RS485_TX_SIZE + sizeof(u32)]; // - эта добавка sizeof() как раз для CRC-поля u32 crc[(MAX_RS485_TX_SIZE + sizeof(u32)) / sizeof(u32)]; // а это чтоб представить весь буфер как набор u32 crc[] }; }; ... void send() { sTxMsgRS485SendCmd tx; tx.hdr.srcAddr = HOST_ADDR; tx.hdr.dstAddr = MBC_ADDR; tx.uid = WORK_REQ_MBC_SEND_RS485; tx.ifNum = 0; u32 const len = /* считал с окошка программы */; u32 i = 0; while(i < len && i < MAX_RS485_TX_SIZE) tx.byte[i] = /* чтение с окошка ввода */()[i++]; tx.len = i; if(i > 0) { i = (i + 3) / 4; // ровняю по u32 u32 const size = sizeof(tx) - (MAX_RS485_TX_SIZE - i * 4); // началось в деревне лето... считаю общий размер кадра tx.crc[i] = crc_Calc(&tx, size / 4 - 1); // фокус с union <- вот он /* ethernet_send() */(&tx); } } Ну вот визуально - полная шляпа выходит)) А хотелось копеечка к копеечке - все заполнили и отправили, без хитрых представлений и закулисных допущений.
  9. Вот я и хотел, чтобы визуально CRC присутствовала в структуре, чтобы и мне (спустя время) и другому человеку было понятно, что содержится в теле пакета. В чем текущее неудобство. Пример. К МК подцеплен езернет и CAN, и пусть это будет некий преобразователь интерфейсов. Езернет цепляется к компу. Комп периодически поллит входящую очередь CAN-а, для чего шлет пакет-запрос READ_CAN_FIFO. МК по этому запросу формирует ответ в виде структуры struct ReadCANAck { Header hdr; CANFrame frame[]; }; Вопрос - где эту структуру создать в памяти. Понимаем, что нижестоящие функции отправки в сеть требуют структуру "целиком", т.е. непрерывным массивом известной длины. Значит можно запихнуть эту структуру в union #define MAX_SEND_MESSAGE_SIZE MAX_ETH_UDP_PAYLOAD_SIZE union SendMessage { ReadCANAck readCANAck; ... ; // возможно, другие "форматки" для других команд u8 buffer[MAX_SEND_MESSAGE_SIZE]; }; Мы заранее не знаем, сколько там в CAN-е может храниться принятых кадров, поэтому после заполнения хедера ответа, мы читаем N кадров CAN-FIFO и заполняем свободное место пэйлоада езернет-фрейма, чуть ли не вот так static SendMessage Tx; void sendCANRxFIFO() { // не насилуем стек - готовим кадр в одном месте Tx.readCANAck.hdr.cmd = READ_CAN_FIFO; // сколько там в CAN фреймов пришло? u32 const frameCnt = CAN.getFrameCnt(); // запихиваем CAN-кадры из его FIFO, пока место в буфере отправки в езернет еще есть for(u32 i = 0; i < frameCnt; ++i) { if(/* места в езернет-фрейме еще хватает ? */) Tx.readCANAck.frame[i] = CAN.readFrame(); } } и вот теперь: беда. Мы договорились, что в протоколе обмена все кадры имеют CRC последним членом. Тут (примера ради) его не было показано. Но этот CRC подразумевался. В структуре ReadCANAck его нельзя после frame[] поставить. И это порождает 2 проблемы: 1) визуально нет поля CRC в пакете - т.е. или я, или сторонний разраб, которому я дам эту структуру, может "забыть", что там еще CRC считать надо и заполнять (а еще и место в памяти выделять!); 2) после заполнения основных указанных полей, в силу "отсутствия" явного описания CRC в структуре отправки - мы должны костыльными приведениями типов и адресацией залезть за последний записанный frame и вставить туда CRC. Это может (и будет!) выглядеть плохо! Так как сходу не будет понятно, с какого лешего мы пишем "за пределы структуры" какую-то там CRC: void sendCANRxFIFO() { ... u32 i; // запихиваем CAN-кадры из его FIFO, пока место в буфере отправки в езернет еще есть for(i = 0; i < frameCnt; ++i) { if(/* места в езернет-фрейме еще хватает ? */) Tx.readCANAck.frame[i] = CAN.readFrame(); } *(u32 *)&Tx.readCANAck.frame[i] = calcCRC32(&Tx, /* правильно посчитать len */); // <- через пару месяцев: WTFFFFFFFFFFFF??? }
  10. Разумное число - у всех разное, поэтому его либо заранее обговаривать в ТЗ, либо пытаться сделать так, чтобы программист вообще об этом не думал - т.е. технически победить ограничение.
  11. Нет не так. Структурой я описываю все содержимое кадра - хедеры, данные и т.д., в том числе CRC. Обрамление кадра - совершенно другая процедура, ее структарми не опишешь. Да и незачем.
  12. Я такие документики тоже делаю - только для такого рода девайсов, где потенциальный заказчик - любой с планеты Земля. А когда надо внутри отдела между парой-тройкой разрабов договориться - никакой писаниной заниматься времени нет.
  13. Нет. Никаких CRC writeTxFIFO() не считает и не дописывает. Условно: void sendTemperature() { ExchDesc<Temperature> t; t.hdr.dst = HOST_PC; t.temp = getTemperature(); t.crc = CRC32(&t, sizeof(t) - 4); SLIP.send(&t, sizeof(t)); // вот внутри нее содержимое 't' обернется в кадр и вызовется writeTxFIFO() }
  14. Да. Так делают, например, топовые гиганты типа интел/амд/нвидиа. И да, я не видел ни одной фирмы, где прям по серьезке садились бы считать байты ОЗУ, которые потребуются для задачи, ибо хотя бы найти челвоека, который это умеет и потом будет в случае чего отвечать - та еще задача. Обычно смотрят по верхушкам - устраивает ли МК/проц по интерфейсам и их скоростям, режимам и т.д. Можно ли его купить в обозримом будущем в тех же объемах, что он продается сейчас. У инженера обычно в комплекте где-то в районе пятой точки есть чуйка, которая подсказывает ему, хватит ли ему ресурсов или будет маловато. Чуйка обучается опытом а потом подтверждается расчетами.
×
×
  • Создать...