заблудился в битах
- Войдите на сайт для отправки комментариев
Втр, 17/05/2016 - 14:23
ошибка странная.... вроде местами работет а местами нет....
есть следующие функции:
//*************************************************************************************************
// процедура возвращает бит (или 1 или 0)
// value - байт источник
// i - номер бита
//*************************************************************************************************
uint8_t GetBit(uint8_t value, uint8_t i) {
return (value << (7-i)) >> 7;
}
//*************************************************************************************************
// процедура устанавливает указаный бит в 1
// value - байт источник
// i - номер бита
//*************************************************************************************************
uint8_t SetBit(uint8_t value, uint8_t i) {
return (B00000001 << i) | value;
}
//*************************************************************************************************
// процедура очищает указаный бит
// value - байт источник
// i - номер бита
//*************************************************************************************************
uint8_t ClearBit(uint8_t value, uint8_t i) {
return (B11111111 ^ (B00000001 << i)) & value;
}
вызываю вот так:
uint8_t Num_byte = Num_ID / 8;
uint8_t Num_bite = Num_ID % 8;
if (GetBit (ActiveSlave[Num_byte], Num_bite) == 0) { return false; }
else { return true; }
при входящих данных:
Num_ID = 96
12й элемент массива в битовом равен 0x00010000
но получаю "true"....
подозреваю, что при сдвиге биты не очищаются ??? вероятно операция идет в 2х байтовом регистре???
чего посоветуете?
вроде есть "volatile", и есть еще директивы компилятора и еще варианты какие... толкните на правильное...
так вроде заработало, но вопрос о причинах остался
uint8_t GetBit(uint8_t value, uint8_t i) { uint8_t a = value << (7-i); return (a >> 7); }vde69, где вы взяли этот getbit? Хрень какая то..
Есть штатный макрос bitRead.
if(bitRead(ActiveSlave[Num_byte], Num_bite) == 0) {returnfalse; }5else{returntrue; }vde69, где вы взяли этот getbit? Хрень какая то..
Есть штатный макрос bitRead.
if(bitRead(ActiveSlave[Num_byte], Num_bite) == 0) {returnfalse; }5else{returntrue; }спасибо, не знал...
0001000
4
Есть штатный макрос bitRead.
Ну, суть-то не в этом, он же хочет понять что не так.
Предполагаю, что последний сдвиг (на 7) выполняется со знаковым выражением, а не беззнаковым, но это нуждается в проверке.
0001000
4
Не, ну давайте Вы реально вставите печать и покажете что печатается, а не будете писать свои предположения.
Я реально хуочу помочь Вам понять почему так, но для этого мне нужны точные вещи - запустите скетч и скопипастите то, что реально напечатается.
ЕвгенийП, вы посмотрите макрос-то. Он двигает в нашем случае число 12 сначала на 7 бит влево, затем на 7 бит вправо. Соответссно функция вернёт обратно первоначальное число 12, ибо счёт идёт в переменной по-умолчанию int
да я реально смотрел еще до поста
dimax, подозреваю что всё ещё проще. Оптимизатор заоптимизирует сдвиги туда-сюда и ничего делаться не будет и вовсе. :)
dimax, подозреваю что всё ещё проще. Оптимизатор заоптимизирует сдвиги туда-сюда и ничего делаться не будет и вовсе. :)
может и так быть, сделал на макросах - вроде работает нормально
Arhat109-2 + 1
совершенно верно, просто компилятор так отбрасывает тотожные операции. когда они в разных строчках, то уже не отбросит.
но можно и надурить, сказав компилу что между операциями надо еще разок привести к типу char
return (uint8_t) (value << (7-i) ) >> 7;
тогда всё сработает как надо.
да я реально смотрел еще до поста
И что, она у Вас прямо так в двоичном виде c незначащими нулями печатает? Ну, как хотите, я действительно хотел помочь.
ЕвгенийП, вы посмотрите макрос-то. Он двигает в нашем случае число 12 сначала на 7 бит влево, затем на 7 бит вправо. Соответссно функция вернёт обратно первоначальное число 12, ибо счёт идёт в переменной по-умолчанию int
Ну, проблема-то явно в описании, но там не всё так просто, value явно описана как байт, так что можно заставить её работать. Просто ТС лень запустить печать и показать, но это уже его беда, а то разобрались бы.
dimax, подозреваю что всё ещё проще. Оптимизатор заоптимизирует сдвиги туда-сюда и ничего делаться не будет и вовсе. :)
Чего? Операцию с переменной
(value << (7-i)) >> 7;
выбросит? Да бросьте. GCC писали не прогеры, уж поверьте.
Чего? Операцию с переменной
(value << (7-i)) >> 7;
выбросит?
Да.
Чего? Операцию с переменной
(value << (7-i)) >> 7;
выбросит?
Да. Даже IAR выбрасывет.
Да.
Когда i - константа - не вопрос, но когда она параметр функции, да ещё и функция не online. Покажите мне ассемблерный код, где она выброшена, пожалуйста.
Давай уже завтра. Но я привел пример, если сказать перед скобками, что надо переменную привести к другому типу (даже к такому-же самому), то компилятор понимает, что надо сначала произвести дейстивия в скобках, приравнять, а потом опять свигать. Иначе он сдвиг влево на 7 и вправо на 7 тупо выкидывает, даже с нулевой оптимизацией. Вам это не долго в симуляторе проверить, минут 10 займет времени.
Хотя Вы тут вроде шарите, даже темы пишете про "размещение переменных" и вдруг такую херню не шарите, десятый класс вроде на информатике.
Так там же влево не на 7, а на (7-i)! А i - параметр функции! Откуда компилятору знать что там прилетит?
ну и что, а теперь математически отбросте семерки, и пусть прилетает что угодно.
у меня с математикой туго, прогуливал, но операций сдвига и какой у них приоритет перед знаками умножения не учил (нет там таких знаков), поэтому так и делаю, как советуют в программировании, либо разносить по разным строкам, либо указать что одни скобки со сдвигом надо таки выполнить и не волнует. Думаю, Вы также делаете.
зы. кстати, ни одна #pragma по выключению оптимизации в этом не поможет. надо самому извращаться.
Выключать оптимизацию потока данных позволяет волешбное слово volatile, о котором Г-программисты, как правило не ведают (они много о чем не ведают, чего нет в учебниках для начинающих .. в частности о размещении глобалов в регистрах .. ждем-пождем вторую часть копипаста учебника)..
__Alexander,
всё-таки я был бы очень благодарен, если бы Вы показали мне ассемблерный код в котором этот сдвиг выброшен. Дело в том, что я воспользовался Вашим советом
и ничего не понял. Понял только то, что
и это, к сожалению, заметно.
Но, поскольку,
даже темы пишете про "размещение переменных" и вдруг такую херню не шарите, десятый класс вроде на информатике.
я решил таки проверить, может и вправду чего-то недогоняю. Если так, то я признаю свою ошибку с благодарностью к указавшему на неё.
Итак, я взял функцию GetBit из кода ТС (скопипастил) и написал вот такой скетч для проверки её на оптимизацию:
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } uint8_t GetBit(uint8_t value, uint8_t i) { return (value << (7-i)) >> 7; } void setup() { Serial.begin(115200); uint8_t number = 231; for (uint8_t n = 0; n < 8; n++ ) { Serial << "N=" << number << "; n=" << n << "; res=" << GetBit(number, n) << "\n"; } } void loop() {}Затем, просто посмотрел в ассемлерный код. Вот он (лишнее выбросил)
Функция GetBit находится в строках 9-27. И что мы в ней видим? Сдвиг вправо на константу действительно соптимизирован. А вот сдвиг влево остался на месте и отрабатывается в цикле в строках 15-20. Никто его не оптимизировал и оптимизировать не мог, насколько я «не шарю».
Другое дело, что из кода чётко видна и проблема ТС, но об этой проблеме уже писал dimax в посте №8. Только вот с оптимизацией эта проблема никак не связана, как видите.
Так что, нет там никакой оптимизации и это следует прямо из кода. Если Вы покажете мне код, где эта операция «соптимизирована», я с большим интересом на него посмотрю.
по поводу "вида" - да уменя приходит не с нулями, у меня приходит в шестнадцеричной чистеме, я штатный монитор порта мне не подходит так как ребутит ардуинку, я написал свой, в нем только вид $hh
в принцепе я вижу 2 возможные причины:
1. операции сдвига проводились в двухбайтовом регистре
2. оптимизатор преобразовал "return (value << (7-i)) >> 7;" к "return (value >> i);"
по поводу "вида" - да уменя приходит не с нулями, у меня приходит в шестнадцеричной чистеме, я штатный монитор порта мне не подходит так как ребутит ардуинку, я написал свой, в нем только вид $hh
Поймите, я попросил Вас дать мне точный код и его вывод. Вы почему-то отказались, даже не знаю почему. Конечно, я могу и сам записать скетч и вывести, но тут есть нюанс: если Вам это не нужно, то мне-то зачем?
в принцепе я вижу 2 возможные причины:
А чего тут видеть? В посте №23 я привёл код в который Ваша функция компилируется - там всё очевидно, проблема решена.
2. оптимизатор преобразовал "return (value << (7-i)) >> 7;" к "return (value >> i);"
Это преобразование неэквивалентно и компилятор не мог такого сделать. Такая идея могла родиться только у Архата, уровень безграмотности которого уже давно ни для кого не секрет.
интересно так будет работать (просто под рукой нет ничего проверить):
uint8_t a = 7;
return (value << (a-i)) >> a;
интересно так будет работать (просто под рукой нет ничего проверить):
uint8_t a = 7; return (value << (a-i)) >> a;
Если прямо так, как у Вас написано, то как раз запросто может соптимизировать - выбросить "a" и использовать константу 7. Проверять нет времени, но здесь он действительно может соптимизировать потому, что компилятору известно чему равно a (и скорее всего соптимизирует). А вот в том случае (из первого поста), компилятору неоткуда знать чему будет равно i потому что это параметр функции, а функция может быть вызвана, например, вообще из другого файла, поэтому там выбросить i он никак не может.
посмотрел асм код, в результате прав был сам топикстартер, почему то идет работа в свзяке R16:R17, т.е. после сдвига, в R16 таки нули, а вот в R17 становится 0x08, и вот загадочные команды
приводят к первоначальному резульату, т.е. к 0x10. Зачем эти команды нужны я пока не понял, да и лень разбираться. При намерянном приведении типа к (char) работа с регистром R17 не ведется и на выходе правильный результат. Одним словом оптимизация тут не при чем.
посмотрел асм код, в результате прав был сам топикстартер,
При намерянном приведении типа к (char) работа с регистром R17 не ведется и на выходе правильный результат. Одним словом оптимизация тут не при чем.
Ну, и слава Богу, что разобрались. Впредь ТС будет знать, что надо промежуточные результаты явно преобразовывать.
Я, кстати, с такой фигнёй никогда не сталкивался, наверное потому, что всегда сильно боюсь, что какой-то сдвиг окажется арифметическим, а не логическим и чтобы этого не случилось, маниакакльно преобразую типы промежуточных результатов везде, где надо и не надо. Наверное, этим и обусловлено, что на такую проблему никогда не нарывался.