|
2 / 2 / 1
Регистрация: 30.07.2016
Сообщений: 118
|
||||||
Вычитание беззнаковых чисел30.08.2017, 20:33. Показов 12323. Ответов 29
Метки нет (Все метки)
При выполнении вот этого кода ,у меня вывод 4294967292 ,не могу понять почему ,помогите пожалуйста ,дайте ссылку на какую нибудь инфу по этой теме
0
|
||||||
| 30.08.2017, 20:33 | |
|
Ответы с готовыми решениями:
29
Сравнение знаковых и беззнаковых чисел Изменение бит в массиве беззнаковых целых чисел
|
|
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
|
|||
| 20.02.2019, 10:32 | |||
![]() К этому времени автор сам допер, чисто научным тыком до явного приведения результата - помогло. Кроме этого, там было сказано что такое явное приведение может приводить к неверной работе кода и делается на свой страх и риск, но опять же без расшифровки в каких случаях. Исследуя вопрос (просматривая результат компиляций от AVR-G++) пока наткнулся на это: uint8_t i; uint8_t *ptr; /*...*/ for( i=0; i<4; i++, ptr++){ /*..*/ } игнорит явно заданный байтовый счетчик цикла и делает его целым, и ещё (пока не понял) похоже дополнительно генерирует скрытый целый счетчик дополнительно для контроля за ptr. Цикл завершается весьма странно по проверке ptr, а не i. Уровень оптимизации Os. Но ещё дизассемблирую код, поскольку такое возникло на не простой функции и 2-х вложенных циклах. На одиноком for() похоже счетчик таки байтовый. Пытаюсь понять не накосячил ли где в коде на С, а то вдруг "зря наезжаю". В общем, вопрос встал в такой форме: КАК можно гарантировать применение именно байтовой арифметики для 8-и разрядных микроконтроллеров для байтовых типов данных? Дело в том, что в С/С++ просто "вагон" разных операций, которые в общем-то все связаны с явным применением укороченных команд типа "инкремент", "декремент" и т.д., что есть у большинства ЦПУ. 8-и битники их имеют но .. в байтовых данных, а вот со словами набор команд часто сильно урезан и получается что использовать "всю прелесть С" - становится нереальным. из-за integer promotions. Так, в частности для AVR: словных команд только пересылка и сложение/вычитание. Даже чтобы положить на регистры словную константу зачастую надо использовать промежуточный регистр (не все позволяют) И 4 команды. Пока что нашел некое замечание, что компилятору можно как-то указать какой размер у "базового целого", но там же примечание что это приведет к проблемам .. тоже пока разбираюсь. Добавлено через 3 часа 16 минут В общем, разобрал тот код .. итого "цикл for есть зло для микроконтроллера" do{}while() - рулит.А вот рекомендация из Апноты AVR035 за то, что все лучше пихать в "объект" - оказалась не верна. Россыпь глобалов дает меньший размер кода. И ещё: работа через указатели не всегда приносит пользу. Обращение kbdKeys[num] к глобалу оказалось компактней и менее затратным. Но, это так .. "побочный результат". А по итогу, да подтвердилось что локальный счетчик for запросто может вырасти до int и ничего с этим не сделать. "Скрытым" оказалась граница указателя и, несмотря на то что у цикла есть счетчик, завершение for определялось по указателю .. несколько странно, но надежно. В общем, для себя вопрос закрыл, ибо насмотрелся на перетасовки данных в регистрах туда-сюда, их локальное переназначение с одного локала на другой в режиме "онлайн" по коду.. "это фантастика". ![]() Мой вывод: хотите писать эффективно и компактно для микроконтроллера - пользуйте Асм. Ничего иного нет. Можно легко сваять прототип на С/С++ и потом допиливать его в Асм, тем более что это не трудно. Оптимизация кода под AVR пока ещё оставляет желать лучшего. В свое время Watcom C справлялся не в пример лучше, ИМХО, так отложилось в памяти. В общем, для себя тему закрыл. Новичкам НАДО тщательно разжевывать integer promotions иначе будут грабли.
0
|
|||
| 20.02.2019, 10:39 | |
|
0
|
|
|
Злостный нарушитель
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,856
|
|
| 20.02.2019, 10:43 | |
|
0
|
|
|
|
||
| 20.02.2019, 10:47 | ||
|
Кстати, операции ++ и -- (возможно, ещё и += и -=) выполняются без promotion Сам по себе promotion не страшен, ибо компилятор всё равно всё соптимизирует. А если машина поддерживает байтовые операции, будет работать именно с ними. Реальная проблема только в warning'ах. Ещё проблему (производительности) может создавать то, что конкретный компилятор под конкретный процессор может не справиться с определённым видом оптимизаций. Но это уже несколько выходит за рамки языка, а упирается в конкретную реализацию. Т.е. требуется опыт работы именно на конкретном компиляторе, с пониманием всех его недоделок Про твой цикл for тоже сложно что-то сказать, ибо в нём вырезаны внутренности, а в тексте ты ссылаешься на них. В итоге можно только гадать, о чём идёт речь Добавлено через 1 минуту Не по теме: Verevkin, на твоём скриншоте видно, что задали вопрос про корову, а ты отвечаешь про шарики
0
|
||
|
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
|
||||||
| 20.02.2019, 11:05 | ||||||
|
вопрос возник с этой функцией:
Вот, если делать байтовый контроль времени антидребезга и удержаний, то возникает поднятая проблема: расширение байтового целого до int приводит к совсем не правильной работе условий if( _time - kbdTime() > interval ){ .. } Им же было найдено решение по явному приведению типа промежуточного результата вычитания к беззнаковому байту. Такие условные операторы в Ардуино для контроля временных интервалов используются "сплошь и рядом", но они во всех примерах на unsigned long, что никаких проблем не вызывает. Хранить для каждой кнопки длинное целое без знака .. ну как-бы "роскошь" ![]() А то, что урезание приведет к неверной работе - просто не ожидалось, вот и возник вопрос "где ещё может скрываться подвох".
0
|
||||||
|
|
|||
| 20.02.2019, 22:09 | |||
|
В этом коде нет циклов, аналогичных тому, который ты привёл в посте #21 и о которых в нём говорил
C ((_time - kbdTime(keyVal)) > KBD_TIME_BOUNCE) C tmp = kbdTime(keyVal); // перед if'ом ... ((_time >= tmp) && ((_time - tmp) > KBD_TIME_BOUNCE)) Добавлено через 2 минуты Хотя... может быть тут есть такое свойство, что _time будет обязательно больше, чем kbdTime(keyVal). Но я не очень понимаю, как можно измерять время в миллисекундах и хранить его в одном байте. Это ведь надо быть уверенным, что между двумя событиями гарантированно меньше, чем 255 миллисекунд
1
|
|||
| 20.02.2019, 22:10 | |
|
0
|
|
|
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
|
|
| 21.02.2019, 06:53 | |
|
Evg, Это "последняя" моя модификация его изделия .. играл тут со счетчиками цикла, решил проверить что раз знаковый поднимается до беззнакового, то может integer promotion остановится на "беззнаковом байте"? Похоже что так.
![]() Для игнорирования дребезга 255мсек - более чем достаточно, но там дополнительно применен свой макрос kbdMillis(), который из unsigned long миллисекунд текущего тика вырезает даже не байт, а только 6 бит кратный по 64мсек (сдвиг вправо на 6 разрядов). Так что у него период опроса в 2U дает задержку для пропуска антидребезга в 128мсек, а период удержания в 63U это около 4 секунд! Как идея - мне очень понравилось. Попробую ваш вариант, посмотрю что будет. В целом, как понял разных авторов на разных ресурсах, для AVR-GCC - явное приведение промежуточного результата - штатное решение по данной проблеме. К сожалению, сейчас и до конца февраля, проверить на Ардуино в реале не смогу .. нет под рукой и не будет. Смогу только посмотреть каков будет результат компиляции и как-то оценить его и только. Добавлено через 8 минут Да, kbdTime() как раз выделяет биты времени из кнопки и имеет uint8_t. Работа всех таких IF() основана как раз на беззнаковом вычитании, когда вычитая из меньшего времени большее начало мы получаем "заем" и .. правильный интервал в беззнаковых величинах. Тут как раз тот случай, когда нужно именно беззнаковое вычитание и integer promotion до знакового - есть грубая ошибка: время 0..255 (uint8_t), интервал срабатывания 2U мсек. "Запуск таймера" произвели на 254 миллисекунде (тоже uint8_t) и? ![]() 1. 255 - 254 = 1, 1>=2U? : false; 2. 0 - 254 = 256(заем!) - 254 = 2, 2>=2U? : true Вот только ради этого заема и нужны беззнаковые байтики
0
|
|
|
|
||
| 21.02.2019, 15:13 | ||
|
C #include <stdio.h> int main (void) { unsigned char a, b, c; a = 0; b = 254; /* Пример N1 */ if ((a - b) > 5u) printf ("1: yes\n"); /* Пример N2 */ c = a - b; if (c > 5u) printf ("2: yes\n"); return 0; } Code $ gcc t.c
$ ./a.out
1: yesЯ правильно понял, в чём твой вопрос? Добавлено через 9 минут В примерах N1 и N2 вычитание строится абсолютно одинаково. Правда во втором примере результат int'ового выражения преобразуется к unsigned char. Итоговое отличие идёт в операции сравнения. В примере N1 сравнение выглядит как (int > unsigned), а в примере N2 - (unsigned char > unsigned). В итоге пример N2 (с учётом преобразования типов при присваивании) отрабатывает как ((int преобразован к unsigned char, а он преобразован к unsigned) > unsigned) а пример N1 как ((int преобразован к unsigned) > unsigned) И именно в этом месте подгадил promotion (т.е. он повлиял на операцию сравнения) Добавлено через 9 секунд В примерах N1 и N2 вычитание строится абсолютно одинаково. Правда во втором примере результат int'ового выражения преобразуется к unsigned char. Итоговое отличие идёт в операции сравнения. В примере N1 сравнение выглядит как (int > unsigned), а в примере N2 - (unsigned char > unsigned). В итоге пример N2 (с учётом преобразования типов при присваивании) отрабатывает как ((int преобразован к unsigned char, а он преобразован к unsigned) > unsigned) а пример N1 как ((int преобразован к unsigned) > unsigned) И именно в этом месте подгадил promotion (т.е. он повлиял на операцию сравнения)
0
|
||
|
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
|
|
| 21.02.2019, 15:54 | |
|
Да, так поняли верно. У меня использована как-бы "скрытая переменная" поскольку вычитание - часть выражения. А у Вас в N2 оно вынесено явно и обратное преобразование к unsigned char компилятор обязан совершить явно.
Похоже что Вы правы не стоит городить сложные выражения с байтовыми данными и promotion должен "выпасть в осадок"... попробую.
0
|
|
| 21.02.2019, 15:54 | |
|
Как создать шаблон функции отдельно для знаковых и беззнаковых чисел
Вычитание восьмеричных чисел Вычитание двоичных чисел Вычитание двух отрицательных чисел Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
| Опции темы | |
|
|
Новые блоги и статьи
|
|||
|
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
|
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет:
1. Использовать системное время и дату,
2. Есть возможность вводить время и дату вручную.
3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
|
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber.
Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
|
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео:
https:/ / vkvideo. ru/ video-240781534_456239017
YouTube:
eY5-5PyI9NM
Текстовая версия
|
|
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать
Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
|
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства.
Родственных связей существует 8 ступеней, такие как:
p - отец
P - мать
q - муж
Q - жена
b - брат
B - сестра
s - сын
S - дочь
|
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире.
Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
|
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С.
Задача:
Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
|