заблудился в битах

vde69
Offline
Зарегистрирован: 10.01.2016

ошибка странная.... вроде местами работет а местами нет....

есть следующие функции:

 

//*************************************************************************************************
// процедура возвращает бит (или 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", и есть еще директивы компилятора и еще варианты какие... толкните на правильное...

vde69
Offline
Зарегистрирован: 10.01.2016

так вроде заработало, но вопрос о причинах остался

uint8_t GetBit(uint8_t value, uint8_t i) {
  uint8_t a = value << (7-i);
  return (a >> 7);
}
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

vde69, где вы взяли этот getbit? Хрень какая то..

Есть штатный макрос bitRead.

if (bitRead(ActiveSlave[Num_byte], Num_bite) == 0) { return false; }

5 else { return true; }

 

vde69
Offline
Зарегистрирован: 10.01.2016

dimax пишет:

vde69, где вы взяли этот getbit? Хрень какая то..

Есть штатный макрос bitRead.

if (bitRead(ActiveSlave[Num_byte], Num_bite) == 0) { return false; }

5 else { return true; }

спасибо, не знал...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015
Вставьте в третью строку (перед if) печать ActiveSlave[Num_byte] и Num_bite
 
Напишите что напечаталось, а там посмотрим
vde69
Offline
Зарегистрирован: 10.01.2016

0001000

4

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dimax пишет:

Есть штатный макрос bitRead.

Ну, суть-то не в этом, он же хочет понять что не так.

Предполагаю, что последний сдвиг (на 7) выполняется со знаковым выражением, а не беззнаковым, но это нуждается в проверке.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vde69 пишет:

0001000

4

Не, ну давайте Вы реально вставите печать и покажете что печатается, а не будете писать свои предположения.

Я реально хуочу помочь Вам понять почему так, но для этого мне нужны точные вещи - запустите скетч и скопипастите то, что реально напечатается.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ЕвгенийП, вы посмотрите макрос-то. Он двигает в нашем случае число 12 сначала на 7 бит влево, затем на 7 бит вправо. Соответссно функция вернёт обратно первоначальное число 12, ибо счёт идёт в переменной по-умолчанию int

vde69
Offline
Зарегистрирован: 10.01.2016

да я реально смотрел еще до поста

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

dimax, подозреваю что всё ещё проще. Оптимизатор заоптимизирует сдвиги туда-сюда и ничего делаться не будет и вовсе. :)

vde69
Offline
Зарегистрирован: 10.01.2016

Arhat109-2 пишет:

dimax, подозреваю что всё ещё проще. Оптимизатор заоптимизирует сдвиги туда-сюда и ничего делаться не будет и вовсе. :)

может и так быть, сделал на макросах - вроде работает нормально

__Alexander
Offline
Зарегистрирован: 24.10.2012

Arhat109-2 + 1

совершенно верно, просто компилятор так отбрасывает тотожные операции. когда они в разных строчках, то уже не отбросит.

но можно и надурить, сказав компилу что между операциями надо еще разок привести к типу char

 return  (uint8_t) (value << (7-i) ) >> 7; 

тогда всё сработает как надо.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vde69 пишет:

да я реально смотрел еще до поста

И что, она у Вас прямо так в двоичном виде c незначащими нулями печатает? Ну, как хотите, я действительно хотел помочь.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dimax пишет:

ЕвгенийП, вы посмотрите макрос-то. Он двигает в нашем случае число 12 сначала на 7 бит влево, затем на 7 бит вправо. Соответссно функция вернёт обратно первоначальное число 12, ибо счёт идёт в переменной по-умолчанию int

Ну, проблема-то явно в описании, но там не всё так просто, value явно описана как байт, так что можно заставить её работать. Просто ТС лень запустить печать и показать, но это уже его беда, а то разобрались бы.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Arhat109-2 пишет:

dimax, подозреваю что всё ещё проще. Оптимизатор заоптимизирует сдвиги туда-сюда и ничего делаться не будет и вовсе. :)

Чего? Операцию с переменной

(value << (7-i)) >> 7;

выбросит? Да бросьте. GCC писали не прогеры, уж поверьте.

__Alexander
Offline
Зарегистрирован: 24.10.2012

ЕвгенийП пишет:

Чего? Операцию с переменной

(value << (7-i)) >> 7;

выбросит? 

Да.

__Alexander
Offline
Зарегистрирован: 24.10.2012

 

ЕвгенийП пишет:

Чего? Операцию с переменной

(value << (7-i)) >> 7;

выбросит? 

Да. Даже IAR выбрасывет.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

__Alexander пишет:

Да.

Когда i - константа - не вопрос, но когда она параметр функции, да ещё и функция не online. Покажите мне ассемблерный код, где она выброшена, пожалуйста.

__Alexander
Offline
Зарегистрирован: 24.10.2012

Давай уже завтра. Но я привел пример, если сказать перед скобками, что надо переменную привести к другому типу (даже к такому-же самому), то компилятор понимает, что надо сначала произвести дейстивия в скобках, приравнять, а потом опять свигать. Иначе он сдвиг влево на 7 и вправо на 7 тупо выкидывает, даже с нулевой оптимизацией. Вам это не долго в симуляторе проверить, минут 10 займет времени.

 

Хотя Вы тут вроде шарите, даже темы пишете про "размещение переменных" и вдруг такую херню не шарите, десятый класс вроде на информатике.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так там же влево не на 7, а на (7-i)! А i - параметр функции! Откуда компилятору знать что там прилетит?

__Alexander
Offline
Зарегистрирован: 24.10.2012

ну и что, а теперь математически отбросте семерки, и пусть прилетает что угодно.

 

у меня с математикой  туго, прогуливал, но операций сдвига и какой у них приоритет перед знаками умножения не учил (нет там таких знаков), поэтому так и делаю, как советуют в программировании, либо разносить по разным строкам, либо указать что одни скобки со сдвигом надо таки выполнить и не волнует. Думаю, Вы также делаете.

 

зы. кстати, ни одна #pragma по выключению оптимизации в этом не поможет. надо самому извращаться.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Выключать оптимизацию потока данных позволяет волешбное слово volatile, о котором Г-программисты, как правило не ведают (они много о чем не ведают, чего нет в учебниках для начинающих .. в частности о размещении глобалов в  регистрах .. ждем-пождем вторую часть копипаста учебника)..

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

__Alexander,

всё-таки я был бы очень благодарен, если бы Вы показали мне ассемблерный код в котором этот сдвиг выброшен. Дело в том, что я воспользовался Вашим советом

__Alexander пишет:
ну и что, а теперь математически отбросте семерки, и пусть прилетает что угодно. 

и ничего не понял. Понял только то, что

__Alexander пишет:
у меня с математикой  туго, прогуливал,

и это, к сожалению, заметно.

Но, поскольку,

__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() {}

Затем, просто посмотрел в ассемлерный код. Вот он (лишнее выбросил)

  16               		.loc 1 3 0
  17               		.cfi_startproc
  18               	.LVL0:
  19               	/* prologue: function */
  20               	/* frame size = 0 */
  21               	/* stack size = 0 */
  22               	.L__stack_usage = 0
  23               		.loc 1 4 0
  24 0000 90E0      		ldi r25,0
  25 0002 27E0      		ldi r18,lo8(7)
  26 0004 30E0      		ldi r19,0
  27 0006 261B      		sub r18,r22
  28 0008 3109      		sbc r19,__zero_reg__
  29 000a 00C0      		rjmp 2f
  30               		1:
  31 000c 880F      		lsl r24
  32 000e 991F      		rol r25
  33               		2:
  34 0010 2A95      		dec r18
  35 0012 02F4      		brpl 1b
  36               	.LVL1:
  37 0014 880F      		lsl r24
  38 0016 892F      		mov r24,r25
  39 0018 881F      		rol r24
  40 001a 990B      		sbc r25,r25
  41               		.loc 1 5 0
  42 001c 0895      		ret
  43               		.cfi_endproc
  44               	.LFE104:
  45               		.size	_Z6GetBithh, .-_Z6GetBithh
  46               		.section	.rodata.str1.1,"aMS",@progbits,1
  47               	.LC0:
  48 0000 4E3D 00   		.string	"N="
  49               	.LC1:
  50 0003 3B20 6E3D 		.string	"; n="
  50      00
  51               	.LC2:
  52 0008 3B20 7265 		.string	"; res="
  52      733D 00
  53               	.LC3:
  54 000f 0A00      		.string	"\n"
GAS LISTING C:\Users\Admin\AppData\Local\Temp\ccoticJG.s 			page 2


  55               		.section	.text.setup,"ax",@progbits
  56               	.global	setup
  57               		.type	setup, @function
  58               	setup:
  59               	.LFB105:
  60               		.loc 1 7 0
  61               		.cfi_startproc
  62 0000 FF92      		push r15
  63               	.LCFI0:
  64               		.cfi_def_cfa_offset 3
  65               		.cfi_offset 15, -2
  66 0002 0F93      		push r16
  67               	.LCFI1:
  68               		.cfi_def_cfa_offset 4
  69               		.cfi_offset 16, -3
  70 0004 1F93      		push r17
  71               	.LCFI2:
  72               		.cfi_def_cfa_offset 5
  73               		.cfi_offset 17, -4
  74 0006 CF93      		push r28
  75               	.LCFI3:
  76               		.cfi_def_cfa_offset 6
  77               		.cfi_offset 28, -5
  78 0008 DF93      		push r29
  79               	.LCFI4:
  80               		.cfi_def_cfa_offset 7
  81               		.cfi_offset 29, -6
  82               	/* prologue: function */
  83               	/* frame size = 0 */
  84               	/* stack size = 5 */
  85               	.L__stack_usage = 5
  86               	.LVL2:
  87               	.LBB40:
  88               	.LBB41:
  89               	.LBB42:
  91               		.loc 2 117 0
  92 000a 26E0      		ldi r18,lo8(6)
  93 000c 40E0      		ldi r20,0
  94 000e 52EC      		ldi r21,lo8(-62)
  95 0010 61E0      		ldi r22,lo8(1)
  96 0012 70E0      		ldi r23,0
  97 0014 80E0      		ldi r24,lo8(Serial)
  98 0016 90E0      		ldi r25,hi8(Serial)
  99 0018 0E94 0000 		call _ZN14HardwareSerial5beginEmh
 100               	.LVL3:
 101 001c C7E0      		ldi r28,lo8(7)
 102 001e D0E0      		ldi r29,0
 103 0020 47E0      		ldi r20,lo8(7)
 104 0022 F42E      		mov r15,r20
 105               	.LBE42:
 106               	.LBE41:
 107               	.LBB43:
 108               	.LBB44:
GAS LISTING C:\Users\Admin\AppData\Local\Temp\ccoticJG.s 			page 5


 109               	.LBB45:
 110               		.loc 1 4 0
 111 0024 07EE      		ldi r16,lo8(-25)
 112 0026 10E0      		ldi r17,0
 113               	.LVL4:
 114               	.L4:
 115               	.LBE45:
 116               	.LBE44:
 117               	.LBB47:
 118               	.LBB48:
 119               		.loc 1 1 0
 120 0028 60E0      		ldi r22,lo8(.LC0)
 121 002a 70E0      		ldi r23,hi8(.LC0)
 122 002c 80E0      		ldi r24,lo8(Serial)
 123 002e 90E0      		ldi r25,hi8(Serial)
 124 0030 0E94 0000 		call _ZN5Print5printEPKc
 125               	.LVL5:
 126               	.LBE48:
 127               	.LBE47:
 128               	.LBB49:
 129               	.LBB50:
 130 0034 4AE0      		ldi r20,lo8(10)
 131 0036 50E0      		ldi r21,0
 132 0038 67EE      		ldi r22,lo8(-25)
 133 003a 80E0      		ldi r24,lo8(Serial)
 134 003c 90E0      		ldi r25,hi8(Serial)
 135 003e 0E94 0000 		call _ZN5Print5printEhi
 136               	.LVL6:
 137               	.LBE50:
 138               	.LBE49:
 139               	.LBB51:
 140               	.LBB52:
 141 0042 60E0      		ldi r22,lo8(.LC1)
 142 0044 70E0      		ldi r23,hi8(.LC1)
 143 0046 80E0      		ldi r24,lo8(Serial)
 144 0048 90E0      		ldi r25,hi8(Serial)
 145 004a 0E94 0000 		call _ZN5Print5printEPKc
 146               	.LVL7:
 147 004e 6F2D      		mov r22,r15
 148 0050 6C1B      		sub r22,r28
 149               	.LBE52:
 150               	.LBE51:
 151               	.LBB53:
 152               	.LBB54:
 153 0052 4AE0      		ldi r20,lo8(10)
 154 0054 50E0      		ldi r21,0
 155 0056 80E0      		ldi r24,lo8(Serial)
 156 0058 90E0      		ldi r25,hi8(Serial)
 157 005a 0E94 0000 		call _ZN5Print5printEhi
 158               	.LVL8:
 159               	.LBE54:
 160               	.LBE53:
 161               	.LBB55:
 162               	.LBB56:
 163 005e 60E0      		ldi r22,lo8(.LC2)
 164 0060 70E0      		ldi r23,hi8(.LC2)
 165 0062 80E0      		ldi r24,lo8(Serial)
GAS LISTING C:\Users\Admin\AppData\Local\Temp\ccoticJG.s 			page 6


 166 0064 90E0      		ldi r25,hi8(Serial)
 167 0066 0E94 0000 		call _ZN5Print5printEPKc
 168               	.LVL9:
 169               	.LBE56:
 170               	.LBE55:
 171               	.LBB57:
 172               	.LBB46:
 173               		.loc 1 4 0
 174 006a B801      		movw r22,r16
 175 006c 0C2E      		mov r0,r28
 176 006e 00C0      		rjmp 2f
 177               		1:
 178 0070 660F      		lsl r22
 179 0072 771F      		rol r23
 180               		2:
 181 0074 0A94      		dec r0
 182 0076 02F4      		brpl 1b
 183 0078 660F      		lsl r22
 184 007a 672F      		mov r22,r23
 185 007c 661F      		rol r22
 186 007e 770B      		sbc r23,r23
 187               	.LBE46:
 188               	.LBE57:
 189               	.LBB58:
 190               	.LBB59:
 191               		.loc 1 1 0
 192 0080 4AE0      		ldi r20,lo8(10)
 193 0082 50E0      		ldi r21,0
 194 0084 80E0      		ldi r24,lo8(Serial)
 195 0086 90E0      		ldi r25,hi8(Serial)
 196 0088 0E94 0000 		call _ZN5Print5printEhi
 197               	.LVL10:
 198               	.LBE59:
 199               	.LBE58:
 200               	.LBB60:
 201               	.LBB61:
 202 008c 60E0      		ldi r22,lo8(.LC3)
 203 008e 70E0      		ldi r23,hi8(.LC3)
 204 0090 80E0      		ldi r24,lo8(Serial)
 205 0092 90E0      		ldi r25,hi8(Serial)
 206 0094 0E94 0000 		call _ZN5Print5printEPKc
 207               	.LVL11:
 208               	.LVL12:
 209               	.LBE61:
 210               	.LBE60:
 211 0098 2197      		sbiw r28,1
 212 009a 00F4      		brcc .L4
 213               	/* epilogue start */
 214               	.LBE43:
 215               	.LBE40:
 216               		.loc 1 13 0
 217 009c DF91      		pop r29
 218 009e CF91      		pop r28
 219               	.LVL13:
 220 00a0 1F91      		pop r17
 221 00a2 0F91      		pop r16
 222 00a4 FF90      		pop r15
GAS LISTING C:\Users\Admin\AppData\Local\Temp\ccoticJG.s 			page 7


 223 00a6 0895      		ret
 224               		.cfi_endproc
 225               	.LFE105:
 226               		.size	setup, .-setup 

Функция GetBit находится в строках 9-27. И что мы в ней видим? Сдвиг вправо на константу действительно соптимизирован.  А вот сдвиг влево остался на месте и отрабатывается в цикле в строках 15-20. Никто его не оптимизировал и оптимизировать не мог, насколько я «не шарю».

Другое дело, что из кода чётко видна и проблема ТС, но об этой проблеме уже писал dimax в посте №8. Только вот с оптимизацией эта проблема никак не связана, как видите.

Так что, нет там никакой оптимизации и это следует прямо из кода. Если Вы покажете мне код, где эта операция «соптимизирована», я с большим интересом на него посмотрю.

vde69
Offline
Зарегистрирован: 10.01.2016

по поводу "вида" - да уменя приходит не с нулями, у меня приходит в шестнадцеричной чистеме, я штатный монитор порта мне не подходит так как ребутит ардуинку, я написал свой, в нем только вид $hh

в принцепе я вижу 2 возможные причины:

1. операции сдвига проводились в двухбайтовом регистре

2. оптимизатор преобразовал "return (value << (7-i)) >> 7;"  к  "return (value >> i);"

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vde69 пишет:

по поводу "вида" - да уменя приходит не с нулями, у меня приходит в шестнадцеричной чистеме, я штатный монитор порта мне не подходит так как ребутит ардуинку, я написал свой, в нем только вид $hh

Поймите, я попросил Вас дать мне точный код и его вывод. Вы почему-то отказались, даже не знаю почему. Конечно, я могу и сам записать скетч и вывести, но тут есть нюанс: если Вам это не нужно, то мне-то зачем?

vde69 пишет:

в принцепе я вижу 2 возможные причины:

А чего тут видеть? В посте №23 я привёл код в который Ваша функция компилируется - там всё очевидно, проблема решена.

vde69 пишет:

2. оптимизатор преобразовал "return (value << (7-i)) >> 7;"  к  "return (value >> i);"

Это преобразование неэквивалентно и компилятор не мог такого сделать. Такая идея могла родиться только у Архата, уровень безграмотности которого уже давно ни для кого не секрет.

 

vde69
Offline
Зарегистрирован: 10.01.2016

интересно так будет работать (просто под рукой нет ничего проверить):

 

uint8_t a = 7;
return (value << (a-i)) >> a;

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vde69 пишет:

интересно так будет работать (просто под рукой нет ничего проверить):

 

uint8_t a = 7; return (value << (a-i)) >> a;

Если прямо так, как у Вас написано, то как раз запросто может соптимизировать - выбросить "a" и использовать константу 7. Проверять нет времени, но здесь он действительно может соптимизировать потому, что компилятору известно чему равно a (и скорее всего соптимизирует). А вот в том случае (из первого поста), компилятору неоткуда знать чему будет равно i потому что это параметр функции, а функция может быть вызвана, например, вообще из другого файла, поэтому там выбросить i он никак не может.

__Alexander
Offline
Зарегистрирован: 24.10.2012

посмотрел асм код, в результате прав был сам топикстартер, почему то идет работа в свзяке R16:R17, т.е. после сдвига, в R16 таки нули, а вот в R17 становится 0x08, и вот загадочные команды

mov R16, R17
ROL R16

приводят к первоначальному резульату, т.е. к 0x10. Зачем эти команды нужны я пока не понял, да и лень разбираться. При намерянном приведении типа к (char) работа с регистром R17 не ведется и на выходе правильный результат. Одним словом оптимизация тут не при чем.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

__Alexander пишет:

посмотрел асм код, в результате прав был сам топикстартер, 

Скорее domax, который давно сказал, что проблема в том, что он промежуточный результат считает int'ом.

__Alexander пишет:

При намерянном приведении типа к (char) работа с регистром R17 не ведется и на выходе правильный результат. Одним словом оптимизация тут не при чем.

Ну, и слава Богу, что разобрались. Впредь ТС будет знать, что надо промежуточные результаты явно преобразовывать.

Я, кстати, с такой фигнёй никогда не сталкивался, наверное потому, что всегда сильно боюсь, что какой-то сдвиг окажется арифметическим, а не логическим и чтобы этого не случилось, маниакакльно преобразую типы промежуточных результатов везде, где надо и не надо. Наверное, этим и обусловлено, что на такую проблему никогда не нарывался.