不使用转换使用十六进制值时的未定义行为

问题描述

这是我遇到过的最奇怪的问题。我正在编程一个国际象棋引擎,并且我有一个返回等级掩码的函数。例如,考虑这个64位的位板。

00000000
00000000
00000000
00000000
00000100
00000000
00000000
00000000

间的1是一块。

现在我的函数应该返回

00000000
00000000
00000000
00000000
11111111
00000000
00000000
00000000

非常简单,只需返回等级的掩码即可。这是我的代码

uint64_t get_rank_mask(int sq)
{
    return (0xFF<<(sq-(sq%8)));
}

这是我通过 36 或正方形的 e5

函数返回的内容
00000000
00000000
00000000
00000000
00000000
00000000
00000000
11111111

嗯,很奇怪。让我对代码做些小的改动。

uint64_t get_rank_mask(int sq)
{
    uint64_t mask = 0xFF;
    mask<<=(sq-(sq%8));
    return  mask;
}

这是现在的返回值

00000000
00000000
00000000
11111111
00000000
00000000
00000000
00000000

神奇的是,这是预期的结果。我什至不知道两个代码示例之间的区别。谁能解释这种行为?

解决方法

0xFFint。假设int具有32位,则将该值左移32位将调用未定义的行为。

在第二个版本中,您以无符号整数类型存储0xFF。可以将其移位任意数量的位,并且该操作已明确定义。在您的情况下,您将其存储在64位无符号int中,因此向左移动32即可得到所需的结果。