Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.96/462: Рейтинг темы: голосов - 462, средняя оценка - 4.96
0 / 0 / 0
Регистрация: 13.12.2014
Сообщений: 4

Как работают побитовые сдвиги?

13.04.2007, 19:36. Показов 88419. Ответов 58
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Люди объясните плиз как работают побитовые сдвиги
<< и >>, а то что то совсем запарился :confused:
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
13.04.2007, 19:36
Ответы с готовыми решениями:

Побитовые сдвиги
#include&lt;iostream&gt; int main() { int t=1; while(255&amp;t){ t=t&lt;&lt;t; std::cout&lt;&lt;t&lt;&lt;'\n';} ...

Побитовые сдвиги
Был на собеседовании, была задачка, вроде такая: Есть функция, которая принимает char a (1 байт) Нужно определить количество битов,...

Побитовые сдвиги
нужна помощь с заданием на С++: При написании функций можно использовать только следующее: - целочисленные константы; - целочисленные...

58
0 / 0 / 0
Регистрация: 30.06.2015
Сообщений: 209
29.12.2017, 11:35
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Kuzia domovenok Посмотреть сообщение
Любая книга по Си.
Поиском я пользоваться умею. Например, эту книгу читаю https://learnc.info/c/bitwise_operators.html когда хочу что-то уточнить.
0
 Аватар для Kuzia domovenok
4268 / 3327 / 926
Регистрация: 25.03.2012
Сообщений: 12,538
Записей в блоге: 1
29.12.2017, 12:02
Цитата Сообщение от design_m Посмотреть сообщение
Но просто не пойму, как это, сдвигая 1 можно не трогать остальные биты в регистре? Когда он пустой, это понятно
ты бы понял, если бы правда читал книги.
Ты же хватаешь по верхам статьи из гугла. Наверное надеешься "по-быстрому выучить С++". Я проверил, эта статья на первых местах в яндексе в выдаче.
Я тебе говорю - сходи в книжный магазин и купи бумажную чёртову книгу, а не гугли вразнобой каждый новый вопрос, что возникает. У тебя клиповое мышление в области программирования формируется.

Добавлено через 4 минуты
Цитата Сообщение от design_m Посмотреть сообщение
Но просто не пойму, как это, сдвигая 1 можно не трогать остальные биты в регистре? Когда он пустой, это понятно
в регистре ты ничего не сдвигаешь. Единственный оператор, который ты применяешь к регистру это |=
Где ты сдвиг увидел? В выражении (1<<RXEN)|( 1<<TXEN) ?
Тебе уже объяснили, что RXEN и TXEN это не регистры. Почему после этого у тебя ещё какие-то вопросы остались?
0
0 / 0 / 0
Регистрация: 30.06.2015
Сообщений: 209
03.01.2018, 01:42
Цитата Сообщение от Kuzia domovenok Посмотреть сообщение
Тебе уже объяснили, что RXEN и TXEN это не регистры.
Так я в курсе.

Добавлено через 2 минуты
Я там выше, когда задавал вопрос, сам об этом писал:
Цитата Сообщение от design_m Посмотреть сообщение
Если надо установить биты 7-0 RXCIE TXCIE UDRIE RXEN TXEN UCSZ2 RXB8 TXB8 регистра UCSRB
C
Выделить код
1
UCSRB=(1<<RXEN)|( 1<<TXEN); //Включаем прием и передачу по USART
Только непонятно, если надо биты RXEN и TXEN установить в единицу,
Добавлено через 6 минут
Зачем же обьяснять человеку то, что он и сам знает?
0
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
14.02.2020, 12:06
Подниму тему, ибо так пишут для микроконтроллеров достаточно часто, забывая что в "стандарте" есть привет из позапрошлого века, а именно: int по умлочанию 32 бита, и числеки из #define часто по умолчанию получают или столько же или, в лучшем случае 16бит, что резко отличается от байтовых регистров микроконтроллеров и в связи с чем возможны разные неожиданности в коде, особенно когда размер сдвига в байтовой переменной.

Но .. как-то надо писать "переносимый код", а управляющие регистры и их битики частенько "гуляют" по описаниям ..

Почему не попробовать так?

C
1
2
3
4
5
6
7
8
9
10
11
12
13
// определяем объединение и побитовую структуру регистра:
typedef union {
  uint8_t r8;
  struct{ reserved1:1, RXEN:1, reserved2:3, TXEN:1, reserved3:2 } bit;
} UART_Controls;
// и сразу за ним "преобразователь к типу":
#define toUART_Controls(d) ((UART_Controls)(d))
// и если надо работать с конкретным регистром мк:
#define U_CSRB toUART_Controls(CSRB)
 
и далее по коду если надо, то примерно так:
 
U_CSRB.bit.RXEN = U_CSRB.bit.TXEN = 1;
Вроде бы оптимизатор должен переварить это вполне нормально. К тому же, такая запись позволяет наглядно видеть в коде структуру управляющих бит в регистрах.. меньше лазить в даташит, что тоже полезно.

Почему не применяется?
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
14.02.2020, 14:05
Arhat109, в стандарте С++ чётко записано - "что записал в union - то и должен считать, а что будет происходить если записал одно, а считал другое - неизвестно". То есть в общем случае твой код может оказаться непереносимым на некоторую абстрактную платформу.
0
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
14.02.2020, 14:12
Цитата Сообщение от TRam_ Посмотреть сообщение
Arhat109, в стандарте С++ чётко записано - "что записал в union - то и должен считать, а что будет происходить если записал одно, а считал другое - неизвестно". То есть в общем случае твой код может оказаться непереносимым на некоторую абстрактную платформу.
Не очень понял. Только что проверял на avr-gcc и avr-g++ .. вроде бы компилирует как надо, но это пока не точно.

А в чем тут плохая переносимость, кроме порядка следования битовых полей в битовой части union? По мне так как раз это честнее и переносимей чем константные сдвиговые операции. Мало того, что размер константы #define не очень-то определено "что это" .. так ещё и сдвиговые операции в стандарте тащат за собой шлейф из древних мэйнфреймов ..

Поясните, если не трудно. Интересно.
0
859 / 448 / 112
Регистрация: 06.07.2013
Сообщений: 1,491
14.02.2020, 14:17
Цитата Сообщение от Arhat109 Посмотреть сообщение
Поясните, если не трудно. Интересно.
Начнем с того, знаешь ли ты что такое Undefined Behavior?
0
 Аватар для COKPOWEHEU
4068 / 2702 / 433
Регистрация: 09.09.2017
Сообщений: 12,019
14.02.2020, 14:23
Ваша запись не позволяет одновременно поменять несколько полей, скажем, при инициализации. Нет, записать в U_CSRB.r8 можно, но там уже совсем другой синтаксис и другие имена констант.
Ну и не все компиляторы умеют эффективно работать с битовыми полями. Я когда-то пытался такое провернуть с портами на avr-gcc и обнаружил, что вместо sbi/cbi он использует чтение-модификацию-запись. Не исключаю, что с тех пор пофиксили.
0
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
14.02.2020, 14:32
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Не исключаю, что с тех пор пофиксили.
Не могу пока понять, как раз хочу проверить. Пока оптимизатор выкидывает вот этот код:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
typedef union _spi_status_u {
  struct _spi_status_b { uint8_t spi2x:1, reserved:5, wcol:1, spif:1; } bit;
  uint8_t reg;
} SpiStatuses;
// converter to SpiStatuses typedef
#define toSpiStatuses(b) ((SpiStatuses)(b))
 
/** Waits for current transmission will be end. Return SPSR, you may contorl WOL bit too. */
static inline uint8_t _spiWait(){
  register SpiStatuses status;
 
  do{
    status.reg = SPSR;
  }while( ~(status.bit.spif) );
  return status.reg;
}
 
/** read from spi to your buffer. "len" - not controlling! Be carefull before calling */
uint8_t spiReadBuf(uint8_t *buf, unsigned int len)
{
  register SpiStatuses status;
  do{
    status.reg = _spiWait();
    if( status.bit.wcol ){ break; }
    *buf++ = SPDR;
  }while(--len);
 
  return status.reg;
}
 
volatile uint8_t glBuffer[100];
 
void setup() {
  spiSetMaster(SPI_DEFAULT);
  glBuffer[0] = spiReadBuf(glBuffer, 100);
}
Оставляя вместо setup() только это:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static inline void spiSetMaster(const uint8_t features){
  SPCR = SPI_SPE|SPI_MSTR|(features);
 276:   80 e5           ldi r24, 0x50   ; 80
 278:   8c bd           out 0x2c, r24   ; 44
  DDRB = (SPI_PIN_SCK)|(SPI_PIN_MOSI)|(SPI_PIN_SS);
 27a:   87 e0           ldi r24, 0x07   ; 7
 27c:   84 b9           out 0x04, r24   ; 4
/** Waits for current transmission will be end. Return SPSR, you may contorl WOL bit too. */
[B]static inline uint8_t _spiWait(){
  register SpiStatuses status;
 
  do{
    status.reg = SPSR;
 27e:   8d b5           in  r24, 0x2d   ; 45
 280:   fe cf           rjmp    .-4         ; 0x27e <main+0xe8>
[/B]
00000282 <_exit>:
 282:   f8 94           cli
Куда девается чтение в буфер - ума не приложу. Уже и буфер волатильный и результат чтения в него складывается ..
Забавно что rjmp безусловный в функции _spiWait() получился ..
0
 Аватар для COKPOWEHEU
4068 / 2702 / 433
Регистрация: 09.09.2017
Сообщений: 12,019
14.02.2020, 15:20
Цитата Сообщение от Arhat109 Посмотреть сообщение
register SpiStatuses status;
А поясните, в чем сакральный смысл этого действия? Я-то думал, вы разместите структуры по нужным адресам и будете работать напрямую с ними. Что-то вроде такого:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <avr/io.h>
#include <stdint.h>
 
union GPIO{
  uint8_t data;
  struct{
    char b0:1;
    char b1:1;
    char b2:1;
    char b3:1;
    char b4:1;
    char b5:1;
    char b6:1;
    char b7:1;
  };
};
 
#define GPIOA (*(volatile union GPIO*)&PORTA)
 
int main(){
  PORTA = 0xFF;
  GPIOA.data = 0x00;
  GPIOA.b4 = 1;
}
Кстати, пофиксили:
Code
1
2
3
4
5
6
7
8
9
int main(){
  PORTA = 0xFF;
  34:   8f ef           ldi     r24, 0xFF       ; 255
  36:   8b bb           out     0x1b, r24       ; 27
  GPIOA.data = 0x00;
  38:   1b ba           out     0x1b, r1        ; 27
  GPIOA.b4 = 1;
  3a:   dc 9a           sbi     0x1b, 4 ; 27
}
0
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
14.02.2020, 20:00
Цитата Сообщение от Raali Посмотреть сообщение
Начнем с того, знаешь ли ты что такое Undefined Behavior?
Видимо на этом и закончим. С Вами на брудершафт вроде не пил, чтобы мне "тыкать", это раз. И второе: если хотите спросить нечто, предоставьте предварительно свои знания по вопросу.

Добавлено через 4 минуты
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
А поясните, в чем сакральный смысл этого действия? Я-то думал, вы разместите структуры по нужным адресам и будете работать напрямую с ними. Что-то вроде такого:
Да в том же самом:
C
1
2
3
do{
    status.reg = SPSR;
}while( ~(status.bit.spif) );
Читаем регистр и проверяем его бит. Можно и напрямую, но конкретно тут, надо его предварительно записать в регистр и потом вернуть как результат. т.к. при чтении эти биты SPIF и WCOL сбрасываются самим фактом чтения. Второй раз узнать была ли ошибка "не получится".

В остальном для той же самой цели..

Добавлено через 3 минуты
P.S.

Так и осталось пока непонятным какого фига оптимизатор выбрасывает кусок кода, и заменяет условное ветвление по флагу на безусловный переход, выкидывая остальной код. И это при том, что регистр SPSR в io.h верно прописан как volatile и присваивается он первому попавшемуся регистру из пула (r24) .. в общем, пока "время кончилось". Позже.

Добавлено через 46 минут
Все же поковырялся ещё немного .. обнаружил такое (вынес все остальное, оставил вообще "оригинал" со сдвигом на константу):

C
1
2
3
4
5
#define _spiWait() { while( ~(SPSR & (1<<SPIF)) ); }
 
void setup() {
  _spiWait();
}
После препроцессора получаем это:
C
1
2
3
4
5
void setup() {
 
  { while( ~((*(volatile uint8_t *)((0x2D) + 0x20)) & (1<<7)) ); };
 
}
То есть как-бы "всё честно", а вот в асме (objdump) с оптимизацией, вижу такой результат:
Assembler
1
2
3
4
5
6
7
void setup() {
// spiSetMaster(SPI_DEFAULT);
  _spiWait();
 1aa:   8d b5           in  r24, 0x2d   ; 45
 1ac:   fe cf           rjmp    .-4         ; 0x1aa <main+0x86>
 
000001ae <_exit>:
Если выключить оптимизатор, то имею:
Assembler
1
2
3
4
5
6
7
8
9
10
  40                .L2:
   8: ****   _spiWait();
  41                    .loc 1 8 0 discriminator 1
  42 0008 8DE4              ldi r24,lo8(77)
  43 000a 90E0              ldi r25,0
  44 000c FC01              movw r30,r24
  45 000e 8081              ld r24,Z
  46 0010 81E0              ldi r24,lo8(1) ; !!! вот тут вместо проверки бита лезет перезапись "1" в регистр ..
  47 0012 8823              tst r24
  48 0014 01F4              brne .L2
Понятно, что после фикс. константы в регистре можно лепить безусловный переход! .. откуда?!?

Добавлено через 10 секунд
Все же поковырялся ещё немного .. обнаружил такое (вынес все остальное, оставил вообще "оригинал" со сдвигом на константу):

C
1
2
3
4
5
#define _spiWait() { while( ~(SPSR & (1<<SPIF)) ); }
 
void setup() {
  _spiWait();
}
После препроцессора получаем это:
C
1
2
3
4
5
void setup() {
 
  { while( ~((*(volatile uint8_t *)((0x2D) + 0x20)) & (1<<7)) ); };
 
}
То есть как-бы "всё честно", а вот в асме (objdump) с оптимизацией, вижу такой результат:
Assembler
1
2
3
4
5
6
7
void setup() {
// spiSetMaster(SPI_DEFAULT);
  _spiWait();
 1aa:   8d b5           in  r24, 0x2d   ; 45
 1ac:   fe cf           rjmp    .-4         ; 0x1aa <main+0x86>
 
000001ae <_exit>:
Если выключить оптимизатор, то имею:
Assembler
1
2
3
4
5
6
7
8
9
10
  40                .L2:
   8: ****   _spiWait();
  41                    .loc 1 8 0 discriminator 1
  42 0008 8DE4              ldi r24,lo8(77)
  43 000a 90E0              ldi r25,0
  44 000c FC01              movw r30,r24
  45 000e 8081              ld r24,Z
  46 0010 81E0              ldi r24,lo8(1) ; !!! вот тут вместо проверки бита лезет перезапись "1" в регистр ..
  47 0012 8823              tst r24
  48 0014 01F4              brne .L2
Понятно, что после фикс. константы в регистре можно лепить безусловный переход! .. откуда?!?

Добавлено через 5 секунд
Все же поковырялся ещё немного .. обнаружил такое (вынес все остальное, оставил вообще "оригинал" со сдвигом на константу):

C
1
2
3
4
5
#define _spiWait() { while( ~(SPSR & (1<<SPIF)) ); }
 
void setup() {
  _spiWait();
}
После препроцессора получаем это:
C
1
2
3
4
5
void setup() {
 
  { while( ~((*(volatile uint8_t *)((0x2D) + 0x20)) & (1<<7)) ); };
 
}
То есть как-бы "всё честно", а вот в асме (objdump) с оптимизацией, вижу такой результат:
Assembler
1
2
3
4
5
6
7
void setup() {
// spiSetMaster(SPI_DEFAULT);
  _spiWait();
 1aa:   8d b5           in  r24, 0x2d   ; 45
 1ac:   fe cf           rjmp    .-4         ; 0x1aa <main+0x86>
 
000001ae <_exit>:
Если выключить оптимизатор, то имею:
Assembler
1
2
3
4
5
6
7
8
9
10
  40                .L2:
   8: ****   _spiWait();
  41                    .loc 1 8 0 discriminator 1
  42 0008 8DE4              ldi r24,lo8(77)
  43 000a 90E0              ldi r25,0
  44 000c FC01              movw r30,r24
  45 000e 8081              ld r24,Z
  46 0010 81E0              ldi r24,lo8(1) ; !!! вот тут вместо проверки бита лезет перезапись "1" в регистр ..
  47 0012 8823              tst r24
  48 0014 01F4              brne .L2
Понятно, что после фикс. константы в регистре можно лепить безусловный переход! .. откуда?!?

Добавлено через 3 минуты
Сайт лежит что-ли? Потрите лишние дубли, пожалуйста!

Добавлено через 3 часа 2 минуты
В общем слегка разобрался, но не понял отчего это компилятор ведет себя именно так.

Кому если интересно, то вся засада в операции побитовой инверсии ~

Выражение внутри while вычисляется неверно при любом варианте перед ней:
C
1
2
3
4
  while( ~(SPSR & (1<<SPIF)) );
  while( ~(SPSR & 0x80 );
  while( ~(SPSR) );
  while( (~(SPSR)) );
Во всех случаях генерируется безусловный переход на начало цикла и весь последующий код выбрасывается.

Это - нормальное поведение?

Добавлено через 8 минут
C
1
2
3
4
5
volatile   unsigned char a = 0xA5;
 
void setup() {
  if( ~a ) SPSR = a;
}
Такой кусок кода также выдает фигню. В регистр сразу присваивается "а" без проверки. С оптимизатором получается даже ещё веселей:
Assembler
1
2
3
4
5
6
7
8
9
volatile   unsigned char a = 0xA5;
 
void setup() {
  if( ~a ) SPSR = a;
  a6:   80 91 00 01     lds r24, 0x0100 ; 0x800100 <__data_start>
  aa:   80 91 00 01     lds r24, 0x0100 ; 0x800100 <__data_start>
  ae:   8d bd           out 0x2d, r24   ; 45
  b0:   08 95           ret
}
О-о-о .. не сразу заметил, что оказывается для последнего случая: warning: promoted ~unsigned is always non-zero [-Wsign-compare] .. с чего бы это?
~0xFF что получим?

Добавлено через 23 минуты
Продолжаем ..
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
union {
  uint8_t reg;
  struct{ uint8_t b0,b1,b2,b3,b4,b5,b6,b7; } bit;
} b;
 
volatile   unsigned char a = 0xa5;
 
void setup() {
  b.bit.b0 = 1;
  
  if( ~b.bit.b0 ) SPSR = a;
  b.reg = a;
  if( ~b.bit.b1 ) SPSR = b.reg;
}
и .. ага, получаем тот же самый warning! Инверсия битового поля НЕ МОЖЕТ быть нулем! Круто, чё..
0
 Аватар для Recrut_rf
389 / 334 / 66
Регистрация: 14.10.2014
Сообщений: 1,474
14.02.2020, 20:05
тема интересная, надо будет изучить ответы пользователей (прям сейчас мне это делать лень )

Kash, для себя я составил небольшую шпаргалку

Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <iostream>
#include <bitset>
 
using namespace std;
 
/*
<<  — сдвиг влево
>>  — сдвиг вправо
~   —  поразрядная инверсия
|    — поразрядное ИЛИ
&  — поразрядное И
^   —  поразрядное исключающее ИЛИ
*/
 
//----------------------------------------------------------------------
//----------------------------------------------------------------------
 
// Если нужно записать сразу несколько бит:
/*
unsigned char x = 0;
x = 1<<номер_бита | 1<<номер_бита | 1<<номер_бита .... ;
 
Номера битов отсчитываются справа налево, начиная с нуля.
0 — это младший бит (справа), 7 — это старший  бит (слева).
*/
 
//----------------------------------------------------------------------
//----------------------------------------------------------------------
 
// Если нужно записывать определенные биты, не стирая другие:
 
// Чтобы записать единицу в бит n:
// x |= (1 << n);
 
// Чтобы записать ноль в бит n:
// x &= ~(1 << n);
 
//----------------------------------------------------------------------
//----------------------------------------------------------------------
 
// Если нужно инвертировать состояние бита:
// x ^= (1 << n);
 
//----------------------------------------------------------------------
//----------------------------------------------------------------------
 
// Если нужно прочитать отдельный бит:
unsigned char x = (1 << 2) | (1 << 3) | (1 << 7);
if (x & (1 << 2)) {  /* во второй бит вписана единица */ }
if (x & (1 << 3)) {  /* в третий бит вписана единица */ }
if (x & (1 << 7)) {  /* в седьмой бит вписана единица */ }
 
//----------------------------------------------------------------------
//----------------------------------------------------------------------
 
// Если нужно определить, что в X на N-й позиции:
bool b = (bool((1 << n)  &  x))
 
//----------------------------------------------------------------------
//----------------------------------------------------------------------
 
// Если нужно обнулить один или несколько битов:
 
//Для обнуления отдельных битов используется оператор & Пример:
int x = 58;       // 00111010
int y = x & 0x0F; // 00001010
 
// Обнулить несколько битов можно и так:
 
x = x & (~((1 << 3) | (1 << 5) | (1 << 6))); //обнуляем третий, пятый и шестой биты
 
//----------------------------------------------------------------------
//----------------------------------------------------------------------
 
//Если нужно установить заданные биты в единицу.Используют оператор |
int x = 155
x = x | 4;     //устанавливаем в единицу второй бит переменной x
 
155     0b10011011
|
4     0b00000100
159     0b10011111
 
 
// Сдвиг влево <<
// Сдвигает число на n разрядов влево
unsigned char x = 3;  //0b00000011
x = x << 3;           //0b00011000 (24)
 
// Сдвиг вправо >>
// Сдвигает число на n разрядов вправо
unsigned char x = 255;  //0b11111111
x = x >> 3;             //0b00011111 (31)
 
 
 
 
int main()
{
    
 
    int n = 0x04;
 
    bitset<8> b(n);
    cout << b << endl;
 
    if ((n & (1 << 3)) == 0)
        cout << " 0 " << endl;
    else
        cout << " 1 " << endl;
 
    bitset<8> f(n);
    cout << f << endl;
 
    /*
    
 
    Если вас интересует буквальное значение бита (т.е. 0 или 1),
    то в языке С значение i-того бита числа n можно получить как
    (n >> i) & 1u
    */
 
    cout << ((n >> 3) & 1u) << endl;
 
    /*
    Если вас интересует взвешенное значение бита (т.е. 0 или 8 для бита номер 3),
    то в языке С значение i-того бита числа n можно получить как
    n & (1u << i)
    (Подразумевается нумерация с нуля от младших битов к старшим.)
    */
 
    //cout << n << endl;
 
    //cout << (n & (1u << 3)) << endl;
 
    /*
    Дано число x. Как установить на место n-ого бита единицу?
    x = x | (1 << n);
    */
    n = n | (1 << 1);
    bitset<8> bb(n);
    
    cout << bb << endl;
 
    return 0;
}



Может вам тоже пригодится
0
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
14.02.2020, 20:19
Перенабирая, ошибся, правильный тест этот:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
union {
  uint8_t reg;
  struct{ uint8_t b0:1,b1:1,b2:1,b3:1,b4:1,b5:1,b6:1,b7:1; } bit;
} b;
 
volatile   unsigned char a = 0xa5;
 
void setup() {
  b.bit.b0 = 1;
  
  if( ~b.bit.b0 ) SPSR = a;
  b.reg = a;
  if( ~b.bit.b1 ) SPSR = b.reg;
}
Результат в асме тотже, только warning даже не показывается.

На этом вопрос можно считать практически закрытым.
0
 Аватар для COKPOWEHEU
4068 / 2702 / 433
Регистрация: 09.09.2017
Сообщений: 12,019
14.02.2020, 22:22
Цитата Сообщение от Arhat109 Посмотреть сообщение
эти биты SPIF и WCOL сбрасываются самим фактом чтения
Судя по Евстифееву, они сбрасываются при чтении SPSR + SPDR, только в паре.
Цитата Сообщение от Arhat109 Посмотреть сообщение
if( ~b.bit.b0 ) SPSR = a;
Почему вы используете побитовую инверсию, а не логическую? Попробуйте использовать правильную.

Добавлено через 7 минут
Поэкспериментировал. В общем-то, результат вполне логичен: поле b0 у вас объявлено как uint8_t. Соответственно, занимает-то оно один бит, но во всех операциях приводится к полноценному типу, 8-битному. А побитовая инверсия 0b00000001 равна (кто бы мог подумать) 0b11111110.
Вывод остается прежним: для логических операций используйте логические, а не побитовые операторы.
1
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
15.02.2020, 17:35
COKPOWEHEU, верно. Логическое отрицание (не бывает логической инверсии) - работает правильно, как и ожидалось.

То, что логический бит приводится к полноценному типу - есть интуитивно, несколько не ожиданное действие, что и показал выше. А самое забавное тут в том, что логическая инверсия "полноценного типа" в виде значения 0xFF не работает так, как ожидается, так как:

~0xFF => ~0b1111_1111 => 0b0000_0000 => 0, не смотря на "warning: promoted ~unsigned is always non-zero [-Wsign-compare]"

Что с этим делать? Ах, да! Там же promoted ..

P.S. К сожалению, как раз в рамках обсуждения имеем полновесный ответ на вопрос "почему не используется объединение с побитовым описанием структуры физического регистра?"

Ответ в вашем сообщении и выше и, сокращая получаем: инверсия бита в С/с++ НЕ может быть нулем .. что есть абсурд для любого управляющего бита, почти любого управляющего регистра .. вот, так и живем.

Добавлено через 2 часа 17 минут
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Судя по Евстифееву, они сбрасываются при чтении SPSR + SPDR, только в паре.
Читаю оригинальный даташит Атмела. Там написано не так. Не уверен, что перевел точно, проверяю как раз.

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Почему вы используете побитовую инверсию, а не логическую? Попробуйте использовать правильную.
Потому что проверял "побитовые операции" в рамках вопроса использования объединений с битовыми структурами .. так оно интуитивно логичней, т.к. работа с отдельным битом.
0
 Аватар для COKPOWEHEU
4068 / 2702 / 433
Регистрация: 09.09.2017
Сообщений: 12,019
15.02.2020, 21:43
Цитата Сообщение от Arhat109 Посмотреть сообщение
инверсия бита в С/с++ НЕ может быть нулем
Но вы же видели, что логическая инверсия единицы равна нулю.
Цитата Сообщение от Arhat109 Посмотреть сообщение
Читаю оригинальный даташит Атмела. Там написано не так. Не уверен, что перевел точно, проверяю как раз.
SPIF is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, the SPIF bit is cleared by first reading the SPI Status Register with SPIF set, then accessing the SPI Data Register (SPDR).
Вроде бы то же самое.
Цитата Сообщение от Arhat109 Посмотреть сообщение
имеем полновесный ответ на вопрос "почему не используется объединение с побитовым описанием структуры физического регистра?"
Полновесного ответа в этой теме вроде бы не было. Скорее всего, побоялись кривизны компилятора (вдруг не догадается использовать sbr/cbr) или просто решили не накручивать оберток вокруг регистров.
Тем более когда биты расположены вразнобой, да еще в нескольких регистрах (таймеры, например). Тут по-человечески вообще не представить.
А может быть просто привычка. Битовые поля это все же экзотика.
В любом случае, вам никто не мешает написать свою реализацию. Хотя бы ради "защиты от дурака" (чтобы нельзя было выставить в регистре бит, которого там нет) пригодится.
0
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
17.02.2020, 07:20
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Вроде бы то же самое.
По отдельности - да, тоже самое. Бит готовности (прерывания) сбрасывается или железом при начале обработке прерывания или программно при первом чтении из регистра статуса.

Проблема в том, что в нем же содержится бит ошибки коллизии передачи - WCOL. К сожалению, он точно также сбрасывается этим самым "первым чтением":

The WCOL bit is set if the SPI Data Register (SPDR) is written during a data transfer. The
WCOL bit (and the SPIF bit) are cleared by first reading the SPI Status Register with WCOL set,
and then accessing the SPI Data Register.

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

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Полновесного ответа в этой теме вроде бы не было.
Ну .. по мне так результат более чем полновесен, хотя Вы - правы: применение логического отрицания решает проблему. Это даже понятно "почему":
Инверсия бита - есть "операция", дающая результат, который подлежит (согласно стандарту) тому самому promoted, что приводит к абсурде согласно ему же и .. может НЕ реализовываться разработчиком компилятора.
То, что как показал это не всегда так .. ну так всегда можно сослаться на разные режимы для promoted и без такового..

А вот логическое отрицание - это работа с флагами процессора и поиск нужного варианта ветвления. И это основное применение "логических операций" .. то, что они побочно дают "результат", который можно сохранять .. ну так опять же можно реализовать проверкой флага и записью с .. все тем же promoted ..

Поэтому логическое отрицание - работает верно. Сначала применяем, и за ненадобностью не делаем promoted, а вот с инверсией - все наоброт: сначала промоутим, а потом смотрим "а что надо-то было?"

Вот эти "тонкости" стандарта и реализаций я и хотел показать этим примерном в разделе "начинающим" .. к сожалению, с "битовой арифметикой" там могут ещё вылезти нюансы (сейчас плохо помню где конректно, но того же плана), вот кмк, поэтому она и не применяется. Надо "смотреть в оба" как за стандартом, так и за компилятором..
0
 Аватар для COKPOWEHEU
4068 / 2702 / 433
Регистрация: 09.09.2017
Сообщений: 12,019
17.02.2020, 10:25
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
reading the SPI Status Register with SPIF set, then accessing the SPI Data Register
Чтение статусного регистра с последующим обращением к SPDR.
Как еще можно описать, что пока не начнете читать-писать в SPDR ничего со статусным регистром не случится?
Цитата Сообщение от Arhat109 Посмотреть сообщение
применение логического отрицания решает проблему
Так никакой проблемы и не было. Было неправильное применение оператора. Ну так и инкремент не годится для инверсии, хотя младший бит меняет - где ж тут проблема?
Цитата Сообщение от Arhat109 Посмотреть сообщение
Вот эти "тонкости" стандарта и реализаций я и хотел показать этим примерном в разделе "начинающим"
Эти ваши измышления даже я не понял, не то что начинающие. Какие-то варианты ветвления, неопределенные поведения и прочее. К чему это все?!
Допустим, вы объявили переменную (поле класса) как struct{int var:1}svar; Формально ее тип все еще int. Соответственно, и для всех операций она будет приводиться к int. А потом результат операции приведется к типу результирующей переменной. Например, double dvar = svar.var+1; приведет к преобразованию int:1 -> int -> double.
Так и у вас: оператор if требует в качестве аргумента целое число. Соответственно, каста к битовому полю и не происходит. Что посчиталось побитовой инверсией, то и попадет в условие.
Другое дело - логическая инверсия (и прочие логические операторы тоже). Вот они приводят результат к диапазону [0,1] независимо от типа аргумента.
1
56 / 20 / 2
Регистрация: 18.06.2018
Сообщений: 199
17.02.2020, 10:46
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Другое дело - логическая инверсия (и прочие логические операторы тоже). Вот они приводят результат к диапазону [0,1] независимо от типа аргумента.
написал тоже самое, иными словами .. "как вижу" что происходит в компиляторе. Сорри, никогда внятно объяснять не умел, спасибо.

Добавлено через 2 минуты
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Допустим, вы объявили переменную (поле класса) как struct{int var:1}svar; Формально ее тип все еще int. Соответственно, и для всех операций она будет приводиться к int. А потом результат операции приведется к типу результирующей переменной. Например, double dvar = svar.var+1; приведет к преобразованию int:1 -> int -> double.
Это и имел ввиду про promoted .. поэтому и не применяется.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
17.02.2020, 10:46

Программа на побитовые сдвиги
Привет! Выполнить путём сдвига вправо все биты, значение которых равно нулю и влево все биты, значение которых равно единице.Т.е. было...

Не работают побитовые операции с++
Использую Microsoft Visual Studio 2012 Express Этот код компилируется, но в переменную с записывается a&amp;&amp;b: #include...

Побитовые сдвиги
Объясните, почему сдвиг битов влево значит умножению на степень двойки. Пример: 6 &lt;&lt; 1 = 6 * 2; 6 &lt;&lt; 3 = 6 * 8; Также...

Побитовые сдвиги
Где применяются побитовые сдвиги и зачем? Вроде не ассемблер учу а тут такое :О

Побитовые сдвиги
Помогите с задачкой :( сопоставить результаты побитового сдвига на*n*бит влево*m&lt;&lt;n* и целочисленного умножения числа*m*на 2n ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
59
Ответ Создать тему
Новые блоги и статьи
сукцессия 6. Питон реализация энилоджиковской модели, картинка про Центральную часть будущей модели
anaschu 26.06.2026
Етить. ИИ мне на основе моего старого файла R создал вот эту вот хмерь на пайтоне. Это уже новая модель, модель сукцессии грибной. потоки фосфора, азота. Углерода. 5 видов организмов. Я даже. . .
Как замкнутый ядерный цикл решит проблему недостатки фосфора? Био миграция фосфора со дна океана
anaschu 26.06.2026
Биологический лифт: Концепция подъема фосфора со дна океана с помощью ЗЯТЦ Предлагаю на обсуждение альтернативу тяжелому промышленному бурению океанического дна. Вместо сложной инженерии мы можем. . .
сукцессия 5
anaschu 26.06.2026
ПЛАН РАЗРАБОТКИ математической модели сукцессии микоризных систем Переход AM → EcM (Endo + ErM) · Шумилов А. С. · ИФХиБПП РАН · Пущино · 2026 . . .
сукцессия 4
anaschu 25.06.2026
Более детализированный план разработки План доработки модели динамики микоризных симбиозов (EcM с гистерезисом) Цель: Реализовать логику переключения между эрикоидным (ErM) и эктомикоризным. . .
сукцессия 3
anaschu 25.06.2026
Примерный план работ по модели
сукцессия 2
anaschu 25.06.2026
параметризировочная калибровочная таблица будущей модели
Многофункциональное здание: как одно здание порождает конфликты требований, которые никто не планировал (мат мет мод 29)
anaschu 23.06.2026
Многофункциональное здание: как одно здание порождает конфликты требований, которые никто не планировал Материалы для обсуждения с МГСУ · 2026 Рисунки внутри приложенного ворд файла. Что за. . .
28. Конкретное развертывание плана номер 1 из поста номер 27
anaschu 22.06.2026
Можно ли из модели получить конкретные строительные требования? Честно — напрямую из текущей модели такие ответы не получить. Но цепочка логики есть, и она не такая длинная. Где разрыв . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru