十六进制整数常量和十进制整数的负整数异或会产生不同的结果吗?
Negative Int XOR with Hexidecimal Integer Constant and Decimal Integer will produce Different Results?
我尝试创建一个 table 'MyTable' 并添加一个字段 "field1" with small int type.
然后我给field1加上一个负数-12289。
然后我执行以下 SQL 查询:
select field1 ^ 0xcfff from MyTable
结果为零。
但是如果我把十六进制整型常量换成十进制整型常量,如下:
select field1 ^ 53247 from MyTable
结果为-65536。
为什么?
Integer constants greater than 2,147,483,647 are converted to the decimal data type, not the bigint data type.
但 0xcfff 和 53247 都比 2,147,483,647 小得多。为什么它们会产生不同的结果?
更新:
根据我的理解,这道题的重点是我们可以将0xcfff转换为small int,像这样:
select cast(0xcfff as smallint)
但是我们不能将 53247 转换为 small int,下面这行会导致溢出:
select cast(53247 as smallint)
这与 C/C++ 不同。在 C/C++ 中,两个转换都可以。
这是因为您的数据长度。
执行按位运算符时应使用相同的字节长度:
1100 1111 1111 1111 <-- -12289 as smallint (word)
1100 1111 1111 1111 <-- CFFF (-12289) (word)
0000 0000 0000 0000 <-- XOR result = 0 (word)
1111 1111 1111 1111 1100 1111 1111 1111 <-- -12289 as int (double word)
0000 0000 0000 0000 1100 1111 1111 1111 <-- 53247 (0000CFFF) (double word)
1111 1111 1111 1111 0000 0000 0000 0000 <-- XOR result = -65536 (double word)
您可以尝试更改长度:
select cast(-12289 as int) ^ 0x00cfff, -12289 ^ cast(0x00cfff as int)
您在这里遗漏的鲜为人知的一点是 Data Type Precedence。您可以通过以下方式查看它:
declare @t table (
Id smallint not null
);
insert into @t (Id)
select -12289;
select sq.*,
sql_variant_property(sq.XBin, 'BaseType') as [BinType],
sql_variant_property(sq.XDec, 'BaseType') as [DecType]
from (
select t.Id,
t.Id ^ 0xcfff as [XBin],
t.Id ^ 53247 as [XDec]
from @t t
) sq;
二进制文字 0xcfff
占用 2 个字节,因此它可以隐式转换为列本身具有的 smallint
类型。然而,十进制文字被解释为 int
(不是因为它需要超过 2 个字节,而是因为 SQL 服务器 always interprets integer literals under 2^32-1 as having this data type, and everything greater interpreted 为 decimal
)。这意味着现在该列必须隐式转换为优先级高于 smallint
的 int
,并且在转换期间保留其符号。
我尝试创建一个 table 'MyTable' 并添加一个字段 "field1" with small int type.
然后我给field1加上一个负数-12289。
然后我执行以下 SQL 查询:
select field1 ^ 0xcfff from MyTable
结果为零。
但是如果我把十六进制整型常量换成十进制整型常量,如下:
select field1 ^ 53247 from MyTable
结果为-65536。
为什么?
Integer constants greater than 2,147,483,647 are converted to the decimal data type, not the bigint data type.
但 0xcfff 和 53247 都比 2,147,483,647 小得多。为什么它们会产生不同的结果?
更新:
根据我的理解,这道题的重点是我们可以将0xcfff转换为small int,像这样:
select cast(0xcfff as smallint)
但是我们不能将 53247 转换为 small int,下面这行会导致溢出:
select cast(53247 as smallint)
这与 C/C++ 不同。在 C/C++ 中,两个转换都可以。
这是因为您的数据长度。 执行按位运算符时应使用相同的字节长度:
1100 1111 1111 1111 <-- -12289 as smallint (word)
1100 1111 1111 1111 <-- CFFF (-12289) (word)
0000 0000 0000 0000 <-- XOR result = 0 (word)
1111 1111 1111 1111 1100 1111 1111 1111 <-- -12289 as int (double word)
0000 0000 0000 0000 1100 1111 1111 1111 <-- 53247 (0000CFFF) (double word)
1111 1111 1111 1111 0000 0000 0000 0000 <-- XOR result = -65536 (double word)
您可以尝试更改长度:
select cast(-12289 as int) ^ 0x00cfff, -12289 ^ cast(0x00cfff as int)
您在这里遗漏的鲜为人知的一点是 Data Type Precedence。您可以通过以下方式查看它:
declare @t table (
Id smallint not null
);
insert into @t (Id)
select -12289;
select sq.*,
sql_variant_property(sq.XBin, 'BaseType') as [BinType],
sql_variant_property(sq.XDec, 'BaseType') as [DecType]
from (
select t.Id,
t.Id ^ 0xcfff as [XBin],
t.Id ^ 53247 as [XDec]
from @t t
) sq;
二进制文字 0xcfff
占用 2 个字节,因此它可以隐式转换为列本身具有的 smallint
类型。然而,十进制文字被解释为 int
(不是因为它需要超过 2 个字节,而是因为 SQL 服务器 always interprets integer literals under 2^32-1 as having this data type, and everything greater interpreted 为 decimal
)。这意味着现在该列必须隐式转换为优先级高于 smallint
的 int
,并且在转换期间保留其符号。