Особенности языка mql5, тонкости и приёмы работы - страница 302

 
Просьба пояснить с побитовыми операциями.
void OnStart()
{
  ushort Num = 0;
    
  Print(typename(Num >> 1)); // int ?!
  
  Num >>= 1; // Здесь делается двойное преобразование: ushort -> int -> ushort?
  
  Num = Num >> 1; // Почему не делается предупреждение, что знаковый int переходит в беззнаковый ushort?
}


Почему побитовая операция приводит к созданию int-переменной?

Как дешево делать побитовые операции?


fxsaber #:
Просьба пояснить с побитовыми операциями.

Это правильно?

void OnStart()
{
  int Num = -1;
  
  Print(Num >> 8); // -1
}


ЗЫ Перенес в эту ветку, т.к. она autotranslate.

 
fxsaber #:
Это правильно?

Да, сдвиг арифметический, код дополнительный.

0xFFFFFFFF сколько не сдвигай, 0xFFFFFFFF и останется.

Если же сдвигаемое значение имеет знаковый тип, то осуществляется арифметический сдвиг вправо, то есть освобождающиеся слева разряды будут заполняться значением знакового бита (если число положительное, то значение знакового бита равно 0, если число отрицательное, то значение знакового бита равно 1)

https://www.mql5.com/ru/docs/basis/operations/bit

 
fxsaber #:

Почему побитовая операция приводит к созданию int-переменной?

Никакого объяснения!

Ошибка (?!) проявляется ТОЛЬКО в промежуточных результатах (для всех побитовых операторов).

Однако присваивание (Num >>= 1) работает, как и ожидалось (к счастью).

void OnStart()
{
  Print(typename((uchar   (3)) >> 1));      // int ?!
  Print(typename((ushort  (3)) >> 1));      // int ?!
  Print(typename((uint    (3)) >> 1));      // uint
  Print(typename((ulong   (3)) >> 1));      // ulong
  Print(typename((char    (3)) >> 1));      // int ?!
  Print(typename((short   (3)) >> 1));      // int ?!
  Print(typename((int     (3)) >> 1));      // int
  Print(typename((long    (3)) >> 1));      // long
  Print(typename((bool    (3)) >> 1));      // int ?!
  Print(typename((color   (3)) >> 1));      // int ?!
  Print(typename((datetime(3)) >> 1));      // datetime

  Print(typename((uchar   (3)) << 1));      // int ?!
  Print(typename((ushort  (3)) << 1));      // int ?!
  Print(typename((uint    (3)) << 1));      // uint
  Print(typename((ulong   (3)) << 1));      // ulong
  Print(typename((char    (3)) << 1));      // int ?!
  Print(typename((short   (3)) << 1));      // int ?!
  Print(typename((int     (3)) << 1));      // int
  Print(typename((long    (3)) << 1));      // long
  Print(typename((bool    (3)) << 1));      // int ?!
  Print(typename((color   (3)) << 1));      // int ?!
  Print(typename((datetime(3)) << 1));      // datetime

  Print(typename((uchar   (3)) & 1));      // int ?!
  Print(typename((ushort  (3)) & 1));      // int ?!
  Print(typename((uint    (3)) & 1));      // uint
  Print(typename((ulong   (3)) & 1));      // ulong
  Print(typename((char    (3)) & 1));      // int ?!
  Print(typename((short   (3)) & 1));      // int ?!
  Print(typename((int     (3)) & 1));      // int
  Print(typename((long    (3)) & 1));      // long
  Print(typename((bool    (3)) & 1));      // int ?!
  Print(typename((color   (3)) & 1));      // int ?!
  Print(typename((datetime(3)) & 1));      // datetime

  Print(typename((uchar   (3)) | 1));      // int ?!
  Print(typename((ushort  (3)) | 1));      // int ?!
  Print(typename((uint    (3)) | 1));      // uint
  Print(typename((ulong   (3)) | 1));      // ulong
  Print(typename((char    (3)) | 1));      // int ?!
  Print(typename((short   (3)) | 1));      // int ?!
  Print(typename((int     (3)) | 1));      // int
  Print(typename((long    (3)) | 1));      // long
  Print(typename((bool    (3)) | 1));      // int ?!
  Print(typename((color   (3)) | 1));      // int ?!
  Print(typename((datetime(3)) | 1));      // datetime
}
 
JRandomTrader #:

Да, сдвиг арифметический, код дополнительный.

0xFFFFFFFF сколько не сдвигай, 0xFFFFFFFF и останется.

https://www.mql5.com/ru/docs/basis/operations/bit

Спасибо, пропустил при прочтении справки.

 
amrali #:

Никаких объяснений!

Ошибка (?!) проявляется ТОЛЬКО в промежуточных результатах (для всех побитовых операторов).

Однако присваивание (Num >>= 1) работает, как и ожидалось (к счастью).

Все интегральные подтипы int обрабатываются внутри как int.
 
Alain Verleyen #:
Все интегральные подтипы int обрабатываются внутри как int.
Похоже на то... Спасибо Алан за объяснение.
 
Alain Verleyen #:
Все интегральные подтипы int внутри обрабатываются как int.

Побитовые операторы преобразуют небольшие целые числа (такие как char/uchar) в знаковые int. https://stackoverflow. com/a/28142065

Интегральные преобразования небольших целых чисел имеют побочные эффекты, о которых следует знать. В следующем примере значение uchar/char может быть сдвинуто влево больше, чем его ширина (<< больше 8 бит).

#define  PrintExpr(A) Print(#A + " = ", (A), " ["+typename(A)+"]")

void OnStart()
{
  PrintExpr((uchar   (1)) << 15);      // = 32768 [int]
  PrintExpr((ushort  (1)) << 15);      // = 32768 [int]
  PrintExpr((char    (1)) << 15);      // = 32768 [int]
  PrintExpr((short   (1)) << 15);      // = 32768 [int]
}

Существует также другая проблема с побитовыми операторами(знаковыми типами):

При выполнении побитовых операций, если вы хотите получить строго определенный (в соответствии со стандартом) результат, вы должны убедиться, что значения, с которыми производятся операции, являются беззнаковыми. Это можно сделать либо с помощью явного приведения, либо используя явно беззнаковые константы (U-суффикс) в бинарных операциях.

 
Alain Verleyen #:
Все интегральные подтипы int обрабатываются внутри как int.

Спасибо.

 
Видимо, потому, что это происходит в 32-битных регистрах процессора.
 
  PrintExpr((uchar)   (1 << 15));      // = 0 [uchar]
  PrintExpr((ushort)  (1 << 15));      // = 32768 [ushort]
  PrintExpr((char)    (1 << 15));      // = 0 [char]
  PrintExpr((short)   (1 << 15));      // = -32768 [short]