Представление шестнадцатеричного числа в десятичном виде с плавающей запятой.
- Войдите на сайт для отправки комментариев
Ср, 28/04/2021 - 18:48
Снимаю показания с неких устройств c помощью ModbusRTU, соответственно получаю ответы, в которых содержатся данные в шестнадцатеричном виде (пример самих данных: 43 6B 58 0E). Далее мне необходимо привести их в понятный большинству десятичный вид. Как раз это у меня не получается...
Не стану приводить код самой программы для простоты восприятия, просто для примера:
void setup() { Serial.begin(9600); } void loop() { double i = 0x436B580E; Serial.println(i, DEC); delay(500); }
В итоге монитор порта выводится следующая цифра: 1131108352.0000000000
Хотя на самом деле 0x436B580E это 235.34375
На форуме искал, но найти не смог, нашёл похожий вопрос в теме Modbus, но пост автора остался без ответа.
Соответственно вопрос: как с помощью ардуиновских средств представить 0x436B580E, как нормальное десятичное число?
а так:
в железе не проверял. так что Neocivic - с вас фидбек. подошло оно для вашей задачи или нет
в железе не проверял.
Да, куда оно денется, работает, конечно
Только я бы не преобразовывал указатели, а сделал бы через union.
b707 - спасибо огромное, контакт есть, показывает правильную цифру 235,34. При этом есть вопрос: можно ли сделать так, чтобы цифры после запятой не обрезались до 2х знаков?
Попытался разобраться в магии Вашего кода, не всё мне понято, пока мои знания слабоваты:
тут всё ясно: присваиваем переменной i значение 0x436B580E. Только в моём случае лучше будет просто long, т.к. некоторые снимаемые значения могут быть отрицательными.
А вот тут возникли проблемы с осознанием. Т.к. float* со звёздочкой, Вы объявили не переменную f, а ссылку с именем f на переменную, которая хранится в ячейке для типа float. подскажите как понять конструкцию после знака "="?
Помогите понять этот код...
При этом есть вопрос: можно ли сделать так, чтобы цифры после запятой не обрезались до 2х знаков?
:))))))))))))))))))))))))))))))))))))
Извини ТС. Это к тебе не относится. Так что-то вспомнилось недавнее)))))))))
:))))))))))))))))))))))))))))))))))))
Извини ТС. Это к тебе не относится. Так что-то вспомнилось недавнее)))))))))
Ответа на мой вопрос нет случайно? :)
:))))))))))))))))))))))))))))))))))))
Извини ТС. Это к тебе не относится. Так что-то вспомнилось недавнее)))))))))
Ответа на мой вопрос нет случайно? :)
Извини друг, я вообще-то новичёк в этом деле, но может найдёшь что-нибудь для себя в моей теме "прошу помощи с функцией". Но лучше спроси опытных людей.
Ответ простой: из щетчика лезет не long, а float (IEEE 754).
С long-ом float объединяет только одно - размер в 4 байта.
Обзовете вы эти 4 байта long, unsigned long, float или byte[4] - контроллеру пофигу.
Единственное, что требуется сделать после приёма данных, - представить 4 байта, как float. Это, вобщем-то, и делает код - ложит в указатель на float адрес какой-то 4-байтовой области памяти.
Всё равно не понимаю, как эта строка работает. Что значит префикс "&" перед переменной?
Берет адрес.
При этом есть вопрос: можно ли сделать так, чтобы цифры после запятой не обрезались до 2х знаков?
цифры обрезаются только при выводе на печать. В памяти МК число лежит с максимальной возможной точностью, которая поддерживается float
Чтобы при выводе печатало больше знаков после запятой, нужно указать функции ПРИНТ, сколько знаков выводить:
- напечатает х с 4 знаками после точки.
Union для этого в c++ запрещен, хоть и работает. иИ есть жалобы на то, что генерируется медленный код. Через указатель на некоторых платформах можно наступить на грабли с выравниванием. Самым универсальным способом считается memcpy.
b707 - спасибо за краткие и понятные ответы.
Иду читать что такое Union и Memcpy :)
Самым универсальным способом считается memcpy.
Т.е. если у нас все преобразования выполняются на этапе компиляции, то код - медленный, а если мы сам контроллер нагружаем дополнительной работой по копированию, то код - быстрый?
если у нас все преобразования выполняются на этапе компиляции
Не пори.
Снова обосрался? Пойди подмойся, дурачок!
Как любил говорить один наш общий знакомый (мудрый мужик!):
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ru-pun
Зачем я продолжаю разговаривать с дурачками?
Как любил говорить один наш общий знакомый (мудрый мужик!):
Так может это... Дума подсуетилась опять? Антисанкции там какие-нить или ещё какая моча в голову вдарила. За этими наперсточниками уследить может только такой истинный профессионал во всех областях человеческой деятельности (включая физиологические), как этот ваш знакомый.
Так может это... Дума подсуетилась опять?
Обама нагадил! Или Байден!
Этот кретин Ркит опять путает стандарт языка и рекомендации МИСРА.
Даже ссылку на МИСРу найти не смог. А я уже заготовил извательский пост о "мисрастах" в нашем отсеке... ;)) Придется придержать.
Причем макают в собственное дерьмо, а он продолжает писать тут. Репутация 3.14здабола, старожилы говнят, а он ну никак не уйдет. Мазохист штоле? И банить вроде не за что, кроме как за тупость.
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ru-pun
не нашел тут формулировки "запрещено". Как оно будет-то... forbidden, not allowed.... or not permitеed ? - простите мой французский...
Кстати. буду признателен, если кто-то из знатоков обьяснит. о какой неопределенности результата в этой ссылке речь?
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ru-pun
Зачем я продолжаю разговаривать с дурачками?
Действительно, зачем? Лучше не разговаривайте.
Если бы Вы умели разговаривать с людьми, Вы бы задали мне вопрос, что имели в виду авторы тех рекомендаций и, возможно, поняли бы, что они там пишут (если бы знаний хватило). Но, поскольку с нормальными людьми Вы разговаривать не умеете, то и не стоит этого делать.
Уточните пожалуйста, по RS485, в случае с Modbus, данные от подчинённых устройств к мастеру в каком виде поступают, как String, char или ещё как?
Чувствую, что что-то глупое спрашиваю, но буду признателен, если проясните?
https://ipc2u.ru/articles/prostye-resheniya/modbus-rtu/
https://ipc2u.ru/articles/prostye-resheniya/modbus-rtu/
Тут я не нашёл ответ на свой вопрос :( Возможно моих знаний недостаточно, чтобы его увидеть. Направьте, если не трудно.
Ваш вопрос неоднозначен. Протокол Modbus RTU предписывает мастеру и слейву обмениваться пакетами, которые состоят из байт. Далее слейв сам должен интерпретировать байты, например как числа. Или как нечисла.
PS. Сорри, зарапортовался. Интерпретирует мастер данные, полученные в ответ от слейва.
Но, лично Вам-то пример не нужен, Вам достаточно источник граблей понимать, а пример, Вы можете и вперёд меня придумать. Источник - это легко.
Разумеется, то, о чём писали авторы верно "в общем случае", но не имеет никакого отношения к рассматриваемому в теме накладыванию long на float. Так что парень-то и впрямь в лужу пукнул, "услышав звон". Но сам по себе звон есть и он правильный.
А в общем случае надо понимать две вещи.
1.
Параграф 6.9(4) стандарта казалось бы прямо говорит, что наложения типа тех, что у авторов статьи, допустимы: "The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T)"
Ну, казалось бы, чего ещё надо - в стандарте прямо сказано, что любой объект типа Т должен занимать sizeof(T) последовательных unsigned char. Ну и почему нельзя накладывать? Можно!
И вправду можно! Но, тут есть нюанс! Также, как и в случае с тернарным оператором веселье начинается, когда типы накладываемых друг на друга сущностей существенно разные и умеют нетривиальным способом преобразовываться друг в друга и в треть типы.
Ну, для разминки, простейшие грабли. Если один из элементов union является volatile, а другой - нет. Уже чувствуете на губах вкус праздника и веселья? :-) Это ж сколько наговнокодить можно!
Или, вот, когда один из накладываемых членов const - как его красиво изменять можно!
Дальше ещё интереснее. Допустим, Вы сделали тип "Рациональное число", состоящий из двух int16_t - числителя и знаменателя и всякие там операции над ним. Операции следят, чтобы знаменатель никогда не оказался нулём и гарантируют это. Теперь Вы наложили этот тип на uint32_t и ... неаккуратной операцией с ним можете запросто угробить своё рациональное число - сделать знаменатель нулём.
А что делать, если у них (членов union) есть конструкторы и деструкторы? А как они собираются преобразовываться к другим типам и друг к другу? А если эти операции требуют изменения той самой памяти, которую они разделяют? Веселье продолжается!
Именно поэтому авторы статьи советуют использовать специальный тип std::byte - он гарантирует, что никаких преобразований никуда не будет - он естественным образом преобразуется во что угодно и что угодно в него. Это решит проблему преобразований. Да и конструкторов с деструкторами у него нет.
Но, если Вы думаете, что это всё, что проблема решена, то ошибаетесь! Show must go on!
2.
Поехали дальше. Концепция памяти предполагает, что одна и та же память не может принадлежать двум объектам (что противоречит самой идее union!). Для разрешения противоречия было введено понятие union active member. Активным членом считается тот, к кому последнему обращались на запись, остальные неактивны и их память типа свободна! Т.е. как только Вы обратились на запись к одному из полей union, у других заканчивается life-time! Доступа к неактивным полям union нет. Более того, нельзя изменить активное поле в константном контексте (хотя, народ предлагает ввести это см. предложение). В стандарте есть такой пример (стр. 264-265 по файлу, что в песочнице) (читайте комментарии!)
Т.е. сначала мы в пятой строке проинициализировали член x и он стал активным. В строке 6 мы доступились к x на чтение - нормально. Потом, в строке 7 мы присвоили значение члену k. Теперь активен k, а x неактивен, его life-time закончился. Поэтому, когда в строке 8 мы пытаемся добраться до x - это ошибка (хотя в реале всё работает - запустите).
Но это же маразм! Что делать-то? Вы не поверите, но дискуссия была очень жаркой. По хорошему, если union противоречит базовой идее устройства памяти, правильно было бы его выбросить из языка. Но хочется же и рыбку скушать, и ... Было даже экзотическое предложение - при потере активности вызывать деструктор объекта, а при любой попытке доступа к неактивному члену (хоть запись, хоть чтение) вызывать конструктор и после этого делать его активным. Было и другое предложение - при любом обращении к неактивному члену, вызывать преобразование типа из типа активного в тип того, к кому обратились и выдавать уже результат преобразования. Но все эти предложения разбивались об разные , порой неочевидные, сложности, связанные с мультитридностью, мальтиядерностью и прочими "мульти" (а это сейчас мэйнстрим - миллионом ядер уже никого не удивишь!).
В итоге, было принято решение объявить, доступ к неактивному объекту - undefined behavior (что и написано в приведённом примере из стандарта и в статье о которой речь) и типа авторы компиляторов - делайте что хотите.
Ну, вот примерно такая здесь история. Но, Вы понимаете насколько это далеко от обсуждаемого в данной теме union'а и насколько нужно было не понимать о чём писали авторы той статьи, чтобы ссылаться на неё в данном обсуждении.
ADDENDUM:
Кстати, хотел написать, но забыл. В решении объявить это «undefined behavior» есть логика.
Помните, мы недавно обсуждали ситуация с переполнением и я тогда цитировал стандарт, что моле если в результате операции в некой переменной получается нечто, не представимое в её типе (например 128 в переменной типа int8_t), то «поведение неопределено». Ну, и здесь то же самое. Выше я говорил о примере наложения рационального числа и uint32_t. Вот смотрите., мы записали длинное целое (оно активно) так, что рациональное сломалось (знаменатель нулём стал). И что будет. если мы попытаемся читать рациональное? Там ведь теперь сидит нечто «не представимое в данном типе» - имеет «неопределённое поведение, точно так же, как когда 128 в int8_t получалось. Т.е. есть тут сквозная логика.
Евгений, спасибо. По прочтению у меня создалось впечатление - возможно обманчивое - что это все как-то очень далеко от меня. Во всяком случае, обмениваться содержимым между двумя сложными обьектами, обьединяя их в union - пока мне в голову не приходило... Хотя... может теперь попробую :)
Я правильно понимаю, что с базовыми типами, типа байтов. интов. лонгов - проблем быть не должно (не считая выравнивания)
Не должно.
Кроме того, в контексте данного форума надо понимать, что выбор компиляторов невелик. А неопределённость она же проявляется как раз при переносе на другой компилятор. А мы этим не занимаемся :-)
Извините за французский
никакой техники безопасности :)
Попытался тут что то про выравнивание написать... А потом удалил нафиг... И так много написано.
Вы бы задали мне вопрос, что имели в виду авторы тех рекомендаций и, возможно, поняли бы, что они там пишут (если бы знаний хватило).
Конечно, куда мне понять рекомендацию "Don’t use a union for type punning". Тут целая диссертация между строк спрятана, когда ты упертый идиот.
куда мне понять
Рад, что до Вас это дошло.
Там, кстати, не одна диссертация, там гораздо больше. Просто авторы не имели возможности писать все подробности (один хрен чайники не поймут половины слов), проще сказать - "не пользуйтесь, а почему - вам знать не обязательно"
Конечно, куда мне понять рекомендацию "Don’t use a union for type punning".
Наконец появилось слово "рекомендация". Нужно за это выпить! Ты ведь понимаешь разницу между:
Я вот говорю тебе не первый раз: "Иди нахрен с форума", а ты не идешь ;)) Вот тут примерно такая же ситуация.
Если бы я обладал правом бана, был бы запрет, а так получается просто рекомендация! ;))
Парни, да у вас тут не скучно!
Всего-то вопрос задал про шестнадцатеричное представление... А столько нового узнал :)
Конечно, куда мне понять рекомендацию "Don’t use a union for type punning".
Я вот говорю тебе не первый раз: "Иди нахрен с форума", а ты не идешь ;))
Сбавьте обороты!!!! rkit - провокатор, но без него будет скуууучно. А вот с ним не соскучишься, как что выскажет, потом на несколько постов не скучно.