|
2 / 2 / 1
Регистрация: 30.07.2016
Сообщений: 118
|
||||||
Вычитание беззнаковых чисел30.08.2017, 20:33. Показов 12285. Ответов 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,855
|
|
| 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 | |
|
Как создать шаблон функции отдельно для знаковых и беззнаковых чисел
Вычитание восьмеричных чисел Вычитание двоичных чисел Вычитание двух отрицательных чисел Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Алиса нашла кучу ошибок компиляции и запуска в проекте, который без проблем компилировался и запускался)))
anaschu 30.06.2026
Я пока посмеюся, но завтра проверю. А вообще интерсно. Дал алисе файл, в котором точно нет ошибок компиляции и запуска, и попросил их найти. Нашла кучу)))
Критические ошибки, мешающие компиляции и. . .
|
сукцессия 16. Общий обзор, в основном что бы другие ии поняли
anaschu 29.06.2026
# Передаточный документ: модель микоризной сукцессии (для нового чата)
Этот документ предназначен для того, чтобы новый чат Claude мог продолжить
работу без необходимости заново разбираться в. . .
|
сукцессия 15 неявная схема
anaschu 29.06.2026
Алиса
Калибровка параметров симбиотической модели: технический обзор
Содержание:
Введение
Постановка проблемы
Технические аспекты реализации
Процесс внедрения изменений
|
сукцессия 14. Обновленная схема модели
anaschu 28.06.2026
ГЛОБАЛЬНАЯ ОПИСАТЕЛЬНАЯ СПЕЦИФИКАЦИЯ ЭКОСИСТЕМНОЙ МОДЕЛИ «SOIL CHEMISTRY & MYCORRHIZA 2. 0»
https:/ / ibb. co/ NnkGpfMd
Представленная интегрированная схема описывает непрерывную нелинейную. . .
|
|
сукцессия 13. Питон модель трехзонного мицелия, пока что в основном арбускулярного
anaschu 28.06.2026
## Разработка агентной модели микоризной сукцессии: от выявления артефактов к созданию комплексной системы
### Аннотация
Представлено исследование по разработке агентной модели микоризной. . .
|
сукцессия 12. краткий список проверок модели перед запуском.
anaschu 27.06.2026
Скрытые отказы в моделях систем динамики (SD-models) экологических систем: два случая из практики
Контекст
Разбирался прототип модели систем динамики (SD-модели) микоризной сукцессии: пять. . .
|
Сукцессия 11. Проверка орудий перед войной: разработка через тестирование
anaschu 27.06.2026
Как не дать модели соврать самой себе: проверки для симуляции микоризной сукцессии
Введение
Когда вы строите математическую модель живой системы — грибов, растений, почвы — главная опасность. . .
|
10 сукцессия. Питон код войны грибов и растений
anaschu 27.06.2026
import numpy as np
class PlantAgent:
def __init__(self, name, strategy, initial_biomass):
self. name = name
self. strategy = strategy # "greedy" (широколиственные) или. . .
|