【发布时间】:2014-01-26 10:49:59
【问题描述】:
这个问题的灵感来自于我尝试回答另一个问题:Converting decimal/integer to binary - how and why it works the way it does?
我能找到的唯一documentation 表示:
x shl y 和 x shr y 操作将 x 的值向左或向右移动 y 位,这(如果 x 是无符号整数)相当于将 x 除以 2^y;结果与 x 的类型相同。例如,如果 N 存储值 01101(十进制 13),则 N shl 1 返回 11010(十进制 26)。请注意,y 的值被解释为以 x 类型的大小为模。因此,例如,如果 x 是整数,则 x shl 40 被解释为 x shl 8,因为整数是 32 位,而 40 mod 32 是 8。
考虑这个程序:
{$APPTYPE CONSOLE}
program BitwiseShift;
var
u8: Byte;
u16: Word;
u32: LongWord;
u64: UInt64;
begin
u8 := $ff;
Writeln((u8 shl 7) shr 7);
// expects: 1 actual: 255
u16 := $ffff;
Writeln((u16 shl 15) shr 15);
// expects: 1 actual: 65535
u32 := $ffffffff;
Writeln((u32 shl 31) shr 31);
// expects: 1 actual: 1
u64 := $ffffffffffffffff;
Writeln((u64 shl 63) shr 63);
// expects: 1 actual: 1
end.
我已经使用 XE3 和 XE5 运行了这个,用于 32 位和 64 位 Windows 编译器,并且输出是一致的,如上面代码中所述。
我预计 (u8 shl 7) shr 7 将完全在 8 位类型的上下文中进行评估。因此,当位移动超出该 8 位类型的末尾时,这些位将丢失。
我的问题是程序为什么会这样。
有趣的是,我将程序翻译成 C++,并在我的 64 位 mingw 4.6.3 上获得了相同的输出。
#include <cstdint>
#include <iostream>
int main()
{
uint8_t u8 = 0xff;
std::cout << ((u8 << 7) >> 7) << std::endl;
uint16_t u16 = 0xffff;
std::cout << ((u16 << 15) >> 15) << std::endl;
uint32_t u32 = 0xffffffff;
std::cout << ((u32 << 31) >> 31) << std::endl;
uint64_t u64 = 0xffffffffffffffff;
std::cout << ((u64 << 63) >> 63) << std::endl;
}
【问题讨论】:
-
我刚刚用 TP55 进行了测试,结果相似(寄存器大小为 16 而不是 32)。所以我猜按位运算默认使用(最大)寄存器大小变量。
-
为什么不直接问Embarcadero?他们应该给你正确的答案
-
来自关于整数类型的 Delphi 3 手册:
Any byte-sized operand is converted to an intermediate word-sized operand that is compatible with both Smallint and Word before any arithmetic operation is performed. -
@LURD 根据文档中的分类,这些是按位运算而不是算术运算:docwiki.embarcadero.com/RADStudio/XE5/Expressions_(Delphi)
-
*,/,div,mod,and,shl,shr,as被归类为乘法运算符。这意味着编译器对它们应用相同的表达式语法。
标签: delphi