What is the behaviour of shl and shr for non register sized operands?

后端 未结 3 1704
广开言路
广开言路 2020-12-17 17:52

This question is inspired by my attempts to answer another question: Converting decimal/integer to binary - how and why it works the way it does?

The only documentat

3条回答
  •  [愿得一人]
    2020-12-17 18:22

    The reason is type promotion:

    One special case of implicit type conversion is type promotion, where the compiler automatically expands the binary representation of objects of integer or floating-point types. Promotions are commonly used with types smaller than the native type of the target platform's ALU prior to arithmetic and logical operations in order to make such operations possible, or more efficient if the ALU can work with more than one type. C and C++ perform such promotion for objects of boolean, character, wide character, enumeration, and short integer types which are promoted to int, and for objects of type float, which are promoted to double. Unlike some other type conversions, promotions never lose precision or modify the value stored in the object.

    So in the following code

    var
      u8: Byte;
    
    begin
      u8 := $ff;
      Writeln((u8 shl 7) shr 7);
    ..
    

    the u8 value is promoted to 32-value before shl; to fix the result you need explicit type conversion:

      Writeln(Byte(u8 shl 7) shr 7);
    

    C++ Standard, Section 4.5 Integral promotions:

    An rvalue of type char, signed char, unsigned char, short int, or unsigned short int can be converted to an rvalue of type int if int can represent all the values of the source type; otherwise, the source rvalue can be converted to an rvalue of type unsigned int.


    To check if Delphi follows the same convention in type promotion I've written the following application:

    var
      u8: Byte;
      u16: Word;
      u32: LongWord;
    
    procedure Test(Value: Integer); overload;
    begin
      Writeln('Integer');
    end;
    
    procedure Test(Value: Cardinal); overload;
    begin
      Writeln('Cardinal');
    end;
    
    begin
      u8 := $ff;
      Test(u8);     // 'Integer'
      u16 := $ffff;
      Test(u16);    // 'Integer'
      u32 := $ffffffff;
      Test(u32);    // 'Cardinal'
      Readln;
    end.
    

    So I believe there should be no difference between Delphi and C++ here.

提交回复
热议问题