|
|
  |
Детская ошибка |
|
|
|
May 23 2016, 21:20
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Оказывается в С++11 структура "булевая алгебра" уже реализована посредством шаблона класса bitset. С одной стороны получается даже излишнее: набор алгебр практически любой размерности, с другой стороны все "bitwise операции" в смысле буля реализованы только между членами класса.
Тогда топикстартовский пример становится корректным в смысле буля, если использовать явное преобразование.
~((bitset<16>)temp1) - инвертирование в смысле буля ~temp1 - ивертирование в смысле алгебры многочленов.
Остается дело за малым: bitset-ы размерности равных основным типам добавить к основным, при этом введя побитовые операции между типами bitset и основными, соответственно добавив функции а-ля "to_ulong" для этих размерностей - чтобы узаконить преобразования по умолчанию. При этом, соответственно поделиться синонимами, так как это непозволительная роскошь попусту транжирить ключевые слова: ~, &, |, ^ - отдать основным битсетам, а comp, bitand, bitor, xor - оставить как есть - нынешним битвайзам. Гуру языка, скорее всего, за такое изменение синтаксиса будет мучительно невыносимо, но зато начинающему большинству, еще не отягощенному знаниями стандарта такая реформа будет естественной.
Сообщение отредактировал aiwa - May 23 2016, 21:21
|
|
|
|
|
May 24 2016, 19:31
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Перечитываю себя и нахожу не совсем то, что хотел донести. От греха подальше поправлюсь. Цитата(GetSmart) (Авто-)Расширение множества решается не созданием многочлена, а только (в смысле только лишь) наличием дополнительного бита у каждого операнда. (Авто-)Расширение множества решается, например, наличием дополнительного бита у каждого операнда. Цитата(aiwa @ May 24 2016, 01:20)  Оказывается в С++11 структура "булевая алгебра" уже реализована посредством шаблона класса bitset. Огласите, пожалуйста, весь список где в С++ отличается результат тильды и побитовой инверсии. Если нет разницы, то зачем платить больше? Применительно к целочисленным и enum операндам. Естественно, без переопределений тильды.
Сообщение отредактировал GetSmart - May 25 2016, 10:01
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
May 25 2016, 01:25
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(GetSmart @ May 24 2016, 22:31)  Огласите, пожалуйста, весь список где в С++ отличается результат тильды и побитовой инверсии. Список не предоставлю по причинам: Во-первых я нигде не утверждал, что результат тильды в С++ отличается от побитовой инверсии. Я только цитировал стандарт, что тильда определена как дополнение, что однозначно указывает принадлежность этой операции к набору операций двоичной арифметики многочленов. Во вторых, также я не утверждал что компилятор компилирует не так как предписывает стандарт: компилятор строго ему следует. Цитата(GetSmart @ May 24 2016, 22:31)  Если нет разницы, то зачем платить больше? Применительно к целочисленным и enum операндам. Естественно, без переопределений тильды. Применительно к целочисленным и enum операндам, разница состоит в том, что приходится платить больше - набором дополнительных служебных слов и ухудшением из-за этого читабельности. в обсуждаемом случае это для избавления от незванного подарка стандартом С++ в виде дополнительных поднятых 16-ти битах: (uint_16)(~var16) Как другой, но более ресурсоемкий вариант: очистить результат маской, либо расширить вручную единичными разрядами. В 98% случаев необходимость в побитовых операциях возникает не как к целочисленным (или enum) типам а именно как к набору бит. 98% я, конечно, написал от фонаря, 1% оставив разработчикам стандарта, другой 1% - прочитавшим стандарт для проверки, если вдруг захочется. Косвенным доказательствам этого является введение в стандарт "по просьбам трудящихся" типа набора бит: bitset. Появился третий вариант альтернативных действий, но тоже дополнительных: ~((bitset<16>)var16). Но в 98% случаях нужно платить больше: набирать лишнее преобразование, захламляя текст, во втором - добавляя еще и команду, а в третьем вызывая еще и конструктор копирования. При этом в оставшихся %2 случаях, текст кода остается "по умолчанию". 98% и 2% логично поменять местами.
|
|
|
|
|
Apr 25 2017, 19:30
|
Участник

Группа: Участник
Сообщений: 20
Регистрация: 27-09-07
Пользователь №: 30 876

|
Помогите пожалуйста восполнить пробел в познаниях языка. почему компилятор может выбрасывать условие if(a==0)? Код void toggle_led ();
void main () { uint16_t i; uint8_t a;
a = 5; for(i = 0; i < 500; i++) { a++; if(a == 0) { toggle_led(); } }
while(1); } ассемблер Код NAME main PUBLIC main SECTION `.text`:CODE:NOROOT(1) THUMB main: ??main_0: B.N ??main_0
END Контроллер STM32F103, IAR ARM 6.10 (проверил и на 7.80), оптимизация по максимуму. toggle_led - внешняя функция, меняет состояние порта. Выбрасывается именно условие if(a==0), если поставить toggle_led без условия, то функция выполняется.
|
|
|
|
|
Apr 26 2017, 05:25
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(vit496 @ Apr 25 2017, 22:30)  Помогите пожалуйста восполнить пробел в познаниях языка. почему компилятор может выбрасывать условие if(a==0)? Видимо оптимизатор компилятора не учитывает возможность переполнения, и для него переменная a принимает значения от 5 до 500. Вообще Ваш код нечитабельный и потенциально опасный, ибо на первый взгляд неочевидно, что a может принимать нулевое значение. В более сложном коде подобный подход это источник багов.
|
|
|
|
|
Apr 26 2017, 05:55
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(vit496 @ Apr 25 2017, 22:30)  Помогите пожалуйста восполнить пробел в познаниях языка. почему компилятор может выбрасывать условие if(a==0)? если Вам таки нужна переменная a вочтобытонистало Код __root uint8_t a;
void main () { uint16_t i; // uint8_t a; a = 5; . . . . Внимательно перечитайте все warn - запустите анализатор кода C-STAT StaticAnalysis (в меню Project). Если оно есть в Вашем IAR/Target
Сообщение отредактировал k155la3 - Apr 26 2017, 05:56
|
|
|
|
|
Apr 26 2017, 07:01
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (Шаманъ @ Apr 26 2017, 08:25)  Видимо оптимизатор компилятора не учитывает возможность переполнения Настолько диких отступлений от стандарта IAR позволять себе не должен. QUOTE 6.2.5 Types 9 The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the representation of the same value in each type is the same. A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type Вот оставить два вызова toggle_led() и пустой цикл мог бы запросто.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 26 2017, 09:33
|
Участник

Группа: Участник
Сообщений: 20
Регистрация: 27-09-07
Пользователь №: 30 876

|
Цитата(Шаманъ @ Apr 26 2017, 09:25)  Видимо оптимизатор компилятора не учитывает возможность переполнения, и для него переменная a принимает значения от 5 до 500. если заменить присваивание a=5 на a=12 (или больше 12), то все работает как надо. Цитата(k155la3 @ Apr 26 2017, 09:55)  Внимательно перечитайте все warn Никаких предупреждений нет. Код __root uint8_t a; с глобальной переменной работает правильно (без __root - тоже). сам проект
Прикрепленные файлы
ux.7z ( 169.51 килобайт )
Кол-во скачиваний: 7
|
|
|
|
|
Apr 26 2017, 15:50
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(Сергей Борщ @ Apr 26 2017, 10:01)  Настолько диких отступлений от стандарта IAR позволять себе не должен. Так не факт, что это преднамеренно. Но судя по этому: Цитата(vit496 @ Apr 26 2017, 12:33)  если заменить присваивание a=5 на a=12 (или больше 12), то все работает как надо. у IARа таки есть проблема.
|
|
|
|
|
Apr 26 2017, 19:10
|
Участник

Группа: Участник
Сообщений: 20
Регистрация: 27-09-07
Пользователь №: 30 876

|
Цитата(GetSmart @ Apr 26 2017, 12:21)  Удалить if компилятор может как из-за условия, так и из-за тела. Условие обозначено вполне корректное. Даже volatile не требуется переменным. А вот содержимое toggle_led() не обозначено. Поэтому утвержтать, что ИАР неправ - преждевременно. toggle_led () Код { GPIOA->ODR ^= GPIO_Pin_0; } Еще. Код ниже исправно выводит в порт значения переменной. А условие не выполняется, какой бы код в него не был бы помещен. Его просто нет в листинге. Код void main () { uint16_t i; uint8_t a;
uart_init(57600);
a = 5; for(i = 0; i < 500; i++) { a++; printf("\ra=%d", a); if(a == 0) { printf("\rxxxxxxx"); } }
while(1); } в терминале: Код ... a=253 a=254 a=255 a=0 a=1 a=2 ...
|
|
|
|
|
Apr 27 2017, 05:59
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(vit496 @ Apr 26 2017, 22:10)  Еще. Код ниже исправно выводит в порт значения переменной. А условие не выполняется, какой бы код в него не был бы помещен. Его просто нет в листинге. Вроде уже объяснили - обычный глюк оптимизатора. Пишите понятные программы и они будут работать безглючно. Как вариант замените a++ на a = (a+1) & 0xFF, ну и расскажите нам заработало ли...
|
|
|
|
|
Apr 27 2017, 07:07
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(vit496 @ Apr 26 2017, 23:10)  toggle_led () Код { GPIOA->ODR ^= GPIO_Pin_0; } Тут три идентификатора (хотя бы один из них) можно объявить так, что компилятор может иметь право их (иногда) удалять в процессе оптимизации. Вместе с чем-то ещё (проверкой условия). Причём неудаление в какой-то ситуации не означает, что компилятор не имеет право удалить в немного другой ситуации. А ещё, неожиданно, может оказаться uint8_t шириной более 8 бит и ИАР окажется прав. Но по логу терминала видно, что он 8-битный. И, если при изменении нач.значения a на 12 код создаётся правильный, то оправдать ИАР не получается. Может оптимизатор на этапе компиляции (почему-то) изменяет ширину переменной до 9 бит, при 12+500 получается как раз 0 в 9-битовой переменной. PS Архив не смотрел.
Сообщение отредактировал GetSmart - Apr 27 2017, 12:04
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Apr 27 2017, 08:05
|
Участник

Группа: Участник
Сообщений: 20
Регистрация: 27-09-07
Пользователь №: 30 876

|
Цитата(Шаманъ @ Apr 27 2017, 09:59)  Вроде уже объяснили - обычный глюк оптимизатора. Пишите понятные программы и они будут работать безглючно.
Как вариант замените a++ на a = (a+1) & 0xFF, ну и расскажите нам заработало ли... нет, ни один из вариантов не помогает, пока переменная 8-ми битная. условие a == 0x100 - то же не выполняется (на случай, если компилятор считает ее более 8 бит). Помогает только использовать переменную 16-бит Код uint16_t a=5; for(i = 0; i < 500; i++) { if(++a >= 0x100) { a = 0; ..... ну раз глюк, то и ладно. Вопрос можно закрыть. Я уж думал, что вообще ничего не понимаю.
Сообщение отредактировал vit496 - Apr 27 2017, 08:14
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|