这是一个用于从LeetCode讨论revering位的C ++类。 https://leetcode.com/discuss/29324/c-solution-9ms-without-loop-without-calculation 例如,给定输入43261596(以二进制表示为00000010100101000001111010011100),返回964176192(以二进制表示为00111001011110000010100101000000)。
有没有人可以解释一下?非常感谢你!
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
struct bs
{
unsigned int _00:1; unsigned int _01:1; unsigned int _02:1; unsigned int _03:1;
unsigned int _04:1; unsigned int _05:1; unsigned int _06:1; unsigned int _07:1;
unsigned int _08:1; unsigned int _09:1; unsigned int _10:1; unsigned int _11:1;
unsigned int _12:1; unsigned int _13:1; unsigned int _14:1; unsigned int _15:1;
unsigned int _16:1; unsigned int _17:1; unsigned int _18:1; unsigned int _19:1;
unsigned int _20:1; unsigned int _21:1; unsigned int _22:1; unsigned int _23:1;
unsigned int _24:1; unsigned int _25:1; unsigned int _26:1; unsigned int _27:1;
unsigned int _28:1; unsigned int _29:1; unsigned int _30:1; unsigned int _31:1;
} *b = (bs*)&n,
c =
{
b->_31, b->_30, b->_29, b->_28
, b->_27, b->_26, b->_25, b->_24
, b->_23, b->_22, b->_21, b->_20
, b->_19, b->_18, b->_17, b->_16
, b->_15, b->_14, b->_13, b->_12
, b->_11, b->_10, b->_09, b->_08
, b->_07, b->_06, b->_05, b->_04
, b->_03, b->_02, b->_01, b->_00
};
return *(unsigned int *)&c;
}
};
答案 0 :(得分:3)
将 cast 视为在内存中提供不同的布局模板。
使用此模板图片,代码是无符号整数存储器位置上32位模板的布局。
因此,不是将内存视为uint32_t
,而是将内存视为32位。
创建指向32位结构的指针。
指针被指定为与uint32_t
变量相同的内存位置。
指针将允许对内存位置进行不同的处理。
创建一个32位(使用该结构)的临时变量。 使用初始化列表初始化变量 初始化列表中的位字段来自原始变量,以相反的顺序列出。
所以,在列表中:
new bit 0 <-- old bit 31
new bit 1 <-- old bit 30
这种方法的基础依赖于初始化列表。 作者让编译器反转这些位。
答案 1 :(得分:3)
该解决方案使用强力来恢复比特。
它声明了一个位域结构(当成员后跟:1
时),每个位为32位,每位一位。
然后通过将输入的地址转换为指向结构的指针,将32位输入视为这种结构。然后c
被声明为该类型的变量,通过恢复位的顺序来初始化。
最后,c
表示的位域被重新解释为整数,你就完成了。
汇编程序不是很有趣,因为gcc资源管理器显示: https://goo.gl/KYHDY6
答案 2 :(得分:2)
它不会按每次转换进行转换,但它只是以不同的方式查看相同的内存地址。它使用int n
的值,但获取指向该地址的指针,对指针进行类型转换,这样,您可以将该数字解释为32个单独位的结构。因此,通过此结构b
,您可以访问该数字的各个位。
然后,对于新的结构c
,通过将数字的第31位放在输出结构c
的第0位,第1位的第30位,等等,来直接设置每个位。
之后,返回结构的内存位置的值。
答案 3 :(得分:2)
首先,发布的代码有一个小bug。这条线
return *(unsigned int *)&c;
如果sizeof(unsigned int)
不等于sizeof(uint32_t)
,则不会返回准确的数字。
该行应为
return *(uint32_t*)&c;
关于它是如何工作的问题,我将尝试用较小的类型uint8_t
解释它。
功能
uint8_t reverseBits(uint8_t n) {
struct bs
{
unsigned int _00:1; unsigned int _01:1; unsigned int _02:1; unsigned int _03:1;
unsigned int _04:1; unsigned int _05:1; unsigned int _06:1; unsigned int _07:1;
} *b = (bs*)&n,
c =
{
b->_07, b->_06, b->_05, b->_04
, b->_03, b->_02, b->_01, b->_00
};
return *(uint8_t *)&c;
}
使用本地结构。本地结构定义为:
struct bs
{
unsigned int _00:1; unsigned int _01:1; unsigned int _02:1; unsigned int _03:1;
unsigned int _04:1; unsigned int _05:1; unsigned int _06:1; unsigned int _07:1;
};
该结构有八个成员。结构的每个成员都是宽度为1
的位域。类型为bs
的对象所需的空间为8
位。
如果将struct
的定义与该类型的变量分开,则该函数将为:
uint8_t reverseBits(uint8_t n) {
struct bs
{
unsigned int _00:1; unsigned int _01:1; unsigned int _02:1; unsigned int _03:1;
unsigned int _04:1; unsigned int _05:1; unsigned int _06:1; unsigned int _07:1;
};
bs *b = (bs*)&n;
bs c =
{
b->_07, b->_06, b->_05, b->_04
, b->_03, b->_02, b->_01, b->_00
};
return *(uint8_t *)&c;
}
现在,让我们说这个函数的输入是0xB7
,它是二进制的1011 0111
。这条线
bs *b = (bs*)&n;
表示:
n
(&n
)bs*
((bs*)&n
)bs *b =
)通过这样做,我们可以选择n
的每一位,并使用b
的成员获取其值。在该行的末尾,
b->_00
的值为1
b->_01
的值为0
b->_02
的值为1
b->_03
的值为1
b->_04
的值为0
b->_05
的值为1
b->_06
的值为1
b->_07
的值为1
声明
bs c =
{
b->_07, b->_06, b->_05, b->_04
, b->_03, b->_02, b->_01, b->_00
};
只需创建c
,使得c
的位与*b
的位相反。
该行
return *(uint8_t *)&c;
表示:
c
。的地址,其值为位模式1110 1101
。uint8_t*
类型的指针。uint8_t
返回uint8_t
,其值与输入参数按位反转。
答案 4 :(得分:0)
这不是混淆,但是一两条评论会帮助无辜者。关键是在变量声明的中间,第一步是识别这里只有一行“代码”,其他一切都是变量声明和初始化。
在声明和初始化之间,我们发现:
} *b = (bs*)&n,
c =
{
这声明了一个变量'b',它是刚刚定义的结构“bs”的指针(*)。然后它将函数参数'n'的地址(unit_32_t)转换为类型指针到bs,并将其分配给'b',有效地创建uint_32_t的 union 和位数组bs 。 然后声明第二个变量,一个名为“c”的实际struct bs,并通过指针'b'初始化它。 b-&gt; _31初始化c._00,依此类推。 因此,在创建“b”和“c”之后,按顺序,除了返回“c”的值之外没有什么可做的。
代码的作者和编译器知道在结构定义结束后,可以在“;”之前创建该类型的变量或与该类型相关的变量,这就是@Thomas Matthews关闭的原因,“作者让编译器反转这些位。“