Преобразовать символ в целое число, оставив кодировку


У меня есть два символа, которые я получаю по Bluetooth.
char a = SerialBT.read();
char b = SerialBT.read();

Согласно справочнику по Arduino, декодированные данные, хранящиеся в char кодируется в текст ASCII.
Я хочу объединить их в Intenger, но следующие методы не работают:

int c = a + b;

int c = (int)a + (int)b;

int c = (a - 48) + (b - 48);

и

String c;
c.setCharAt(0, a);
c.setCharAt(1, b);

Спасибо

, 👍0

Обсуждение

Предложение «_декодированные данные, хранящиеся в char, кодируются в текст ASCII_» не имеет смысла: a и b содержат полученные данные _как есть_, без какого-либо кодирования/декодирования. Все методы, которые вы показываете, _должны работать_, но делают разные вещи. Чего именно вы пытаетесь достичь, «объединяя» персонажей? Пожалуйста, покажите пример данных, которые у вас есть, и результат, который вы хотите., @Edgar Bonet

@ Эдгар Бонет, во-первых, спасибо за ответ. Вот пример: я получаю десятичные числа 49 и 50. Я сохраняю их в два отдельных символа, a и b. Теперь я хочу сделать одно число (c) из двух символов (a и b). Когда я пробую методы, показанные в моем сообщении, это не работает., @Python Schlange

Что вы подразумеваете под «_это не работает_»? Какое числовое значение вы ожидаете от c?, @Edgar Bonet

Я ожидаю, что это будет значение ASCII., @Python Schlange

«Что вы имеете в виду под «это не работает»?» - Я получаю десятичное значение, а не ASCII. Извините, не ясно написал., @Python Schlange

Значение ASCII чего? Пожалуйста, ответьте на мой вопрос: если a равно 49, а b равно 50, то каким должно быть значение c?, @Edgar Bonet

@PythonSchlange Ты так и не объяснил толком, что ты получаешь и чего хочешь. Получаете ли вы данные в кодировке ASCII (как это делает Serial Monitor)? Или вы получаете простые целые числа? И какое значение в каком типе вы ожидаете на выходе? Строка "4950"? Целое число со значением 4950? Или 49 и 50 - это десятичные значения двух байтов целочисленного значения?, @chrisl

a в примере «49», что равно 1 в ASCII, и b «50», что равно 2. Я ожидаю, что в конце c будет 12., @Python Schlange

Вы имеете в виду что-то вроде c = 10*(a-48) + b-48;?, @StarCat

@StarCat Спасибо!, @Python Schlange


2 ответа


Лучший ответ:

2

Хорошо, после длинных просьб о разъяснениях выяснилось, что вы получаете число в десятичном формате ASCII ("12") и хотите проанализировать в целое число.

Вы можете использовать метод parseInt() последовательного объекта, например:

int c = SerialBT.parseInt();

Однако это может сильно замедлить работу программы, так как parseInt() использует тайм-аут, чтобы знать, когда перестать ожидать больше цифр.

Если вы уже прочитали байты, вы можете объединить их с помощью простых арифметика:

int c = 10 * (a - '0') + (b - '0');

Обратите внимание, что '0' совпадает с 48, только делает более явным цель вашего кода.

,

Большое спасибо! Теперь работает. Но я получаю десятичное число, просто для оформления., @Python Schlange


1

Используйте маску AND, чтобы преобразовать символ в цифру:

int c = 10 * (a & 0x0F) + (b & 0x0F);

Когда была изобретена ASCII, цифры от 0 до 9 были закодированы в шестнадцатеричном виде как от 30 до 39 до включить простое преобразование в/из цифр и символов.

Чтобы преобразовать цифру в ASCII ИЛИ байт с 0x30:

byte digit = 5;
char character = digit | 0x30;

Чтобы преобразовать символ в цифру, И это с 0x0F:

char character = '5';
byte digit = character & 0x0F;

Эти логические операторы быстрее и эффективнее, чем математические операции + и -.

,

Каким образом эти операторы быстрее и эффективнее? Двоичный & и вычитание занимают один такт для AVR. Imo это только сделает ваш код менее читаемым (сделает менее понятным, что он на самом деле делает)., @StarCat

Также обратите внимание, что преобразование byte() не имеет никакого эффекта, так как оно отменяется последующим [интегральным продвижением](https://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_promotion). Вы можете просто написать character & 0x0f., @Edgar Bonet

@starcat, Что касается удобочитаемости: да, я согласен, но это стандартные преобразования с момента появления ASCII, и они очень хорошо известны, поэтому распознаются с первого взгляда. Многие люди пишут свои собственные макросы или встроенные функции, чтобы сделать их более читабельными. Что касается скорости и эффективности: схемы & и | в процессоре проще, потребляют меньше энергии и завершаются за меньшую часть тактового цикла. Что касается AVR: это всего лишь один из многих, которые могут использовать больше тактов., @tim

@edgar-bonet, это для упаковки байта в инструкцию по сборке вместе с кодом операции, как это делают многие процессоры., @tim

@EdgarBonet, [ANDI — логическое И с немедленным выполнением] (https://i.stack.imgur.com/2V6Fr.png) из [Руководство по набору инструкций AVR, стр. 36] (http://ww1.microchip.com/downloads /en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf), @tim

По поводу «_скорости и эффективности_»: я сомневаюсь, что вы сэкономите простой пикоджоуль, заменив вычитание побитовым и. Вы должны предоставить фактические данные измерений, если хотите утверждать, что разница в потреблении энергии между «суби» и «анди» по крайней мере измерима, не говоря уже о том, что она актуальна в реальной жизни. Насчет «_упаковки байта в ассемблерную инструкцию_»: это не имеет смысла. Семантически character & byte(0x0F) означает int(character) & int(byte(0x0F)) согласно правилам языка. Практически вы получаете одну и ту же сгенерированную сборку независимо от того, выполняете ли вы приведение или нет., @Edgar Bonet

Упаковка байта в инструкцию является стандартной практикой. Для инструкции AVR ANDI непосредственный байт **K**константы разбивается на [два полубайта, помеченных KKKK...KKKK] (https://i.stack.imgur.com/2V6Fr.png )., @tim

Какова твоя точка зрения? Какое отношение это имеет к обсуждению? Та же «упаковка» (называемая «непосредственным» операндом) применяется к команде вычитания «subi». И вы получаете одну и ту же инструкцию сборки независимо от того, используете ли вы приведение к байту или нет., @Edgar Bonet

Я только что скомпилировал тест, используя побитовое ИЛИ | для uint_8 и еще один для int в VS для x86. Он учитывал приведения типов, то есть movzx eax,byte ptr [digit] и mov eax,dword ptr [int_digit], но это не является окончательным, поскольку это 32-битный процессор, поэтому он использовал 32-битный | для обоих, что все еще более эффективно, чем использование схемы сумматора или вычитателя. Для 8-битного процессора AVR следует использовать инструкцию ANDI. Какой компилятор вы используете, который не учитывает приведения типов?, @tim

А энергосбережение важно, например, для продления срока службы батареи., @tim

@EdgarBonet, я только что скомпилировал тест в AVR gcc 9.2.0. Он использовал lds r24,digit, ori r24,lo8(48) для byte, а lds r24,int_digit, lds r25,int_digit+1, ori r25,3 для байта. инт. Так что это тоже чтит типовые приведения. Какой компилятор вы используете, который не учитывает приведения типов?, @tim

-1 за превращение отличного ответа из 5 абзацев в школьный отчет., @VE7JRO

Извините, @VE7JRO. Это было в ответ на комментарии EdgarBonet., @tim

@VE7JRO, подумав, я мог бы вернуться к предыдущей версии, потому что я думаю, что StarCat и EdgarBonet просто троллили. Посмотрим, как пойдет пока. Я собирался также добавить раздел об эффективности логических вентилей... диссертацию!, @tim

@tim - Почему бы вам не добавить максимальное количество символов в свой ответ, чтобы сделать его еще лучше !!! Я думаю, что ограничение составляет 30 000 символов на сообщение (ПОДСКАЗКА: «за сообщение»). Все на планете знают, что чем длиннее ответ, тем лучше :), @VE7JRO

Кстати, @VE7JRO, если вы думали, что это отличный ответ, почему вы не проголосовали за него до того, как я его добавил? :) И у меня есть синтезатор Quartus, чтобы доказать эффективность логического элемента ИЛИ с двумя входами по сравнению со схемой полного сумматора. РЖУ НЕ МОГУ, @tim

@tim - Сеть Arduino Stack Exchange дает каждому пользователю ограниченное количество голосов в день (может быть, 24?). Я не думал, что ваш ответ стоит того, чтобы проголосовать за него, когда вы впервые опубликовали его, поэтому я не проголосовал за него. Вы являетесь членом SO - Stack Exchange в течение шести с половиной лет, поэтому процесс голосования за/против не должен быть для вас сюрпризом., @VE7JRO

@tim, троллинг? Нет, это был настоящий комментарий. Я не видел (и до сих пор не вижу) смысла такой оптимизации как ответа на этот конкретный вопрос. Это может быть полезно в других ситуациях, когда важен высокий уровень оптимизации. Только не здесь. Я просто не верю, что это полезный ответ., @StarCat

Я пробовал как с avr-g++ 5.4.0 (поставляется с Ubuntu 18.04), так и с avr-g++ 7.3.0 (из Arduino 1.8.13). Оба игнорируют приведение типов, как и должно быть в соответствии с правилами языка (читайте о «интегральном продвижении C++»). Обратите внимание, что ваш тест ошибочен: вы меняете не только приведения типов, но также типы и значения данных: сгенерированная сборка, очевидно, должна быть другой. Прочитайте мой первый комментарий: я только что написал, что character & byte(0x0f) эквивалентно character & 0x0f. Это все, что можно сравнить. PS: похоже, вы скомпилировали с уровнем оптимизации 0. Никто бы никогда так не сделал., @Edgar Bonet

Спасибо @tim за еще одну душу, но путь StarCat и Эдгара Бонета проще. Мне не нужна более быстрая душа в этом проекте, так как это не даст мне никакого преимущества. Но в любом случае, спасибо., @Python Schlange

@EdgarBonet, я пробовал int i1 = c1 & char(0x0f); и int i1 = c1 & char(0x0f0f); Оба дали andi r24,15, поэтому он соблюдал приведение типов. Я также пробовал int i1 = c1 & int(0x0f); и int i1 = c1 & int(0x0f0f); Первый дал andi r24,15, оптимизированный, потому что 15 помещается в байте; последний дал 'andi r24,15', 'andi r25,15'., @tim

@PythonSchlange, спасибо за комплимент. Хотя это может не понадобиться в вашем конкретном проекте, это важно для продуктов с батарейным питанием и продуктов с низким энергопотреблением в целом, потому что это снижает энергопотребление. В этом нет ничего нового, & и | были эффективным методом в течение последних 60 лет. Математические операторы представляют собой деградацию первоначального замысла ASCII от «30» до «39» в шестнадцатеричном формате., @tim

@StarCat, хорошо, ты не троллил, и тогда я дал тебе настоящий ответ. ОП не указал, какой уровень оптимизации им нужен, поэтому я просто дал 60-летний отраслевой стандартный метод. Однако из-за оптимизации компилятора можно удалить приведения типов, чтобы сделать его более читабельным., @tim

Относительно «_стандартного отраслевого метода_»: это действительно было стандартом в те времена, когда вы делали это с помощью специальной схемы. Если вы считаете, что это все еще является «отраслевым стандартом», когда это делается сегодня на современном процессоре, пожалуйста, предоставьте ссылку. В противном случае я бы сказал, что это не более чем [карго-культ](https://en.wikipedia.org/wiki/Cargo_cult_programming)., @Edgar Bonet

На тему «_это важно для продуктов с батарейным питанием_»: важно? Действительно? Вы явно не боитесь гипербол... Я провел некоторые [фактические измерения] (https://gist.github.com/edgar-bonet/7afbf8b1df02534ac142cf84bb12e87a), чтобы увидеть разницу. Я приглашаю вас взглянуть. Спойлер: это далеко не «необходимо»., @Edgar Bonet

@EdgarBonet, каково значение [нагрузочного резистора внутри вашего Arduino] (https://www.arduino.cc/en/Tutorial/DigitalPins) на PD2 для «SUBI»? И каково значение вашего подтягивающего резистора на PD2 для ANDI? Каково энергопотребление этого внутреннего подтягивающего резистора при замыкании на землю через PD2 для теста «ANDI»?, @tim

@EdgarBonet, вместо того, чтобы быть «несколько удивительным», это очень предсказуемо и очевидно как для профессионального инженера-конструктора, так и для любителя. Хотя вы «пришли к выводу», что разница в 1% (в пользу «SUBI») была незначительной, вам необходимо рассмотреть более широкую картину реального мира. Сколько символов ASCII от «30» до «39» пересылается через Интернет и преобразуется в/из «0» в «9»? Каково энергопотребление этого множества? Доля в 1 % от [огромного числа](https://www.google.com/search?q=internet+energy+consumption) — это все равно много энергии., @tim

Внутреннее (и единственное) подтягивание составляет около 30 кОм. Вытяжки нет. Обратите внимание, что для теста «andi» я отключил PD2 перед измерением, чтобы на него не влиял подтягивающий ток. Ваше замечание об энергопотреблении всего Интернета совершенно не в тему на этом Arduino-ориентированном сайте., @Edgar Bonet

Некоторая (по крайней мере) разность токов выглядит так, как если бы внутренний подтягивающий резистор оставался закороченным на землю через PD2 на протяжении всего теста «ANDI». Что касается контекста этого сайта, совершенно уместно выделить снижение энергопотребления, особенно в связи с IoT, для которого широко используются Arduino. Кроме того, вы расширили тему, упомянув «реальные приложения» в своей ссылке на GitHub. Принцип использования | и & был здравым в 1960 году и остается верным и по сей день, тем более с сегодняшним масштабом использования., @tim

1. Как я уже говорил, внутренняя подтяжка была отключена от массы, пока я замерял потребление. 2. Я не собираюсь расширять контекст. Интернет вещей, микроконтроллеры и даже Arduino можно увидеть в реальных приложениях. 3. Я не оспариваю, что & - это звуковой вариант. Я оспариваю, что «существенно» (ваше слово) предпочесть вычитание. 4. Эта дискуссия зашла слишком далеко. [Дополнение к stackoverflow] (https://stackoverflow.com/q/63862117)., @Edgar Bonet

@ VE7JRO, я вернулся к «совершенно хорошему ответу». Не могли бы вы отменить голосование, пожалуйста?, @tim

@tim - Нет проблем :) Теперь нам просто нужен модератор, чтобы переместить эти комментарии в чат, где они должны быть. Робот SE генерирует «флаг» для мода при 20 комментариях, а у нас сейчас до 32 комментариев., @VE7JRO