我正在尝试学习C编程,我正在研究一些源代码,有一些我不理解的东西,特别是关于Bitwise运算符。我在这上面阅读了一些网站,我对他们的工作有了一个了解,但当我回过头来查看这些代码时,我无法理解他们使用的原因和方式。
我的第一个问题与按位运算符无关,而是与ascii magic有关:
有人可以向我解释以下代码的工作原理吗?
char a = 3;
int x = a - '0';
我理解这是将char转换为int,但我不理解它背后的逻辑。为什么/如何运作?
现在,关于按位运算符,我觉得我真的迷失了。
这段代码做了什么?
if (~pointer->intX & (1 << i)) { c++; n = i; }
我在某处读到了〜反转位,但是我没有看到这句话是做什么的,为什么会这样做。
与此行相同:
row.data = ~(1 << i);
其他问题:
if (x != a)
{
ret |= ROW;
}
| =运算符到底在做什么?从我读到的,| =是OR,但我不太明白这句话是做什么的。
有没有办法重写这段代码,以便更容易理解,以便它不使用这个按位运算符?我发现他们很容易理解,所以希望有人能指出我正确的方向,了解他们如何更好地工作!
我现在对按位运算符有了更好的理解,现在整个代码更有意义。
最后一件事:似乎没有人回应是否有一种“更清洁”的方式来重写这段代码的方式更容易理解,也许不是“bitlevel”。有什么想法吗?
答案 0 :(得分:17)
这将产生垃圾:
char a = 3;
int x = a - '0';
这是不同的 - 请注意引号:
char a = '3';
int x = a - '0';
char
数据类型存储标识字符的数字。数字0到9的字符在字符代码列表中彼此相邻,所以如果从“9”的代码中减去“0”的代码,则得到答案9.所以这将转为数字将字符代码转换为数字的整数值。
(~pointer->intX & (1 << i))
如果if
语句不为零,那么它将被解释为真。使用了三种不同的按位运算符。
〜运算符翻转数字中的所有位,因此如果pointer->intX
为01101010
,则~pointer->intX
将为10010101
。 (注意,在整个过程中,我说明了一个字节的内容。如果它是一个32位整数,我必须写入32位的1和0)。
&amp;运算符通过分别处理每个位将两个数字组合成一个数字。如果两个输入位均为1,则结果位仅为1.因此,如果左侧为00101001
且右侧为00001011
,则结果为00001001
。
最后,<<
表示左移。如果你从00000001开始并将它移动三个位置,那么你将有00001000.所以表达式(1&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot; i)产生一个值,其中i开启,其他的都关闭。
将所有内容放在一起,它会测试i
中的pointer->intX
位是否已关闭(零)。
所以你可以弄明白~(1 << i)
的作用。如果i
为4
,则括号中的内容为00010000
,因此整个内容为11101111
。
ret |= ROW;
那个相当于:
ret = ret | ROW;
|
运算符与&
类似,不同之处在于,如果任一输入位为1
,则结果位为1。因此,如果ret
为00100000
且ROW
为00000010
,则结果为00100010
。
答案 1 :(得分:0)
ret |= ROW;
相当于
ret = ret | ROW;
答案 2 :(得分:0)
单引号用于表示使用单个字符。因此'0'是char'0',它具有ASCII码48。 3-'0' = 3-48
'1&lt;&lt; i'向左移动1个位置,因此只有右边的第i个位是1.
〜pointer-&gt; intX否定字段intX,因此当intX除了右边的第i位以外的每一位都没有设置时,逻辑AND返回一个真值(不是0)。
答案 3 :(得分:0)
char a = '3';
int x = a - '0';
你这里有一个拼写错误(请注意3的左右),这将字符3的ascii值分配给char变量,然后下一行取'3' - '0'并将其分配给x ,由于ascii值的工作方式,x将等于3(整数值)
在第一次比较中,我从未见过〜之前用过指针,可能是另一个错字?如果我要读出以下代码:
(~pointer->intX & (1 << i))
我会说“(从指针取消引用的intX值)AND(1次左移i次)”
1&lt;&lt; i是将1乘以2的幂的快速方法,即如果i是3,则1 <&lt;&lt; 3 == 8
在这种情况下,我不知道为什么要反转指针的位。
在第二次比较中,x | = y与x = x |相同ÿ
答案 4 :(得分:0)
对于char a = 3; int x = a - '0';
,我认为你的意思是char a = '3'; int x = a - '0';
。很容易理解,如果你意识到在ASCII中数字按顺序排列,如'0','1','2',......所以如果'0'是48而'1'是49,那么'1 ' - '0'是1。
对于按位操作,在开始查看位之前很难掌握它们。当您在二进制数字上查看这些操作时,您可以确切地看到它们的工作方式......
010 & 111 = 010
010 | 111 = 111
010 ^ 111 = 101
~010 = 101
答案 5 :(得分:0)
我想你可能有一个错字,意思是:
char a = '3';
这样做的原因是所有数字都按顺序排列,“0”是第一个。显然,'0' - '0'= 0.'1' - '0'= 1,因为'1'的字符值比'0'的字符值大1。等
答案 6 :(得分:0)
1)char实际上只是一个8位整数。 '0'== 48,以及所暗示的一切。
2)(〜(指针 - &gt; intX)&amp;(1&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot; i))评估无论指针指向的intX成员中的'i'位(来自右侧)是否未设置。 〜反转比特,所以0都变为1,反之亦然,则1&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;我把一个1放在所需的位置,&amp;将这两个值组合在一起,只保留所需的位,如果该位为0,则整个事件的评估为真。
3)|是按位还是。它接受两个操作数中的每一位并执行逻辑OR,产生一个结果,如果任一操作数设置了该位,则每个位都置位。 0b11000000 | 0b00000011 == 0b11000011。 | =是赋值运算符,与a + = b表示a = a + b,a | = b表示a = a | b的方式相同。
不使用按位运算符CAN在某些情况下使事情更容易阅读,但如果没有强大的编译器优化,它通常也会使代码显着变慢。
答案 7 :(得分:0)
您引用的减法技巧有效,因为ASCII数字按升序排列,从零开始。因此,如果ASCII'0'的值为48(并且是),则'1'的值为49,'2'为50等。因此ASCII('1') - ASCII('0')= 49 - 48 = 1。
就位运算符而言,它们允许您对变量执行位级操作。
让我们打破你的榜样:
(1 << i)
- 这是将常数1左移i位。因此,如果i = 0,则结果为十进制1.如果i = 1,则将第一位向左移,用零回填,产生二进制0010或十进制2.如果i = 2,则将第二位移到向左,用零回填,产生二进制0100或十进制4等
~pointer->intX
- 这是取指针的intX成员的值并反转其位,将所有零设置为1,反之亦然。
&
- &符运算符执行按位AND比较。如果表达式的左侧和右侧都是1,则结果为1,否则为0。
如果pointer->intX
在右边的第i个位置有0位,那么测试将会成功。
此外,|=
表示进行按位OR比较,并将结果分配给表达式的左侧。对于左侧或右侧相应位为1的每个位,按位OR的结果为1,
答案 8 :(得分:0)
1)有人可以向我解释以下代码的工作原理吗? char a = 3; int x = a - '0'; 我承诺这样做是为了将char转换为int,但是我不理解它背后的逻辑。为什么/如何运作?
不确定。变量 a 的类型为char,并且通过将单引号放在0附近,导致C将其视为char。最后,整个语句自动强制转换为整数等价,因为 x 被定义为整数。
2)现在,关于按位运算符,我觉得我真的迷失了。 ---这段代码做了什么? if(~strient-&gt; intX&amp;(1&lt;&lt; i)){c ++; n = i;我在某处读到了〜反转位,但是我没看到这句话是做什么的,为什么会这样做。
(~pointer->intX & (1 << i)) is saying:
否定intX,并且AND将其向左移位1位
所以,如果intX = 1011,i = 2,等于
(0100 & 0100)
-negate 1011 = 0100
-(1 << 2) = 0100
0100 & 0100 = 1 :)
然后,如果AND操作返回1(在我的例子中,它确实如此) {c ++; n = i; }
所以,将c递增1,并将变量n设为i
与此行相同:row.data =〜(1&lt;&lt;&lt;&lt; i);
Same principle here.
Shift a 1 to the left by i places, and negate.
So, if i = 2 again
(1 << 2) = 0100
~(0100) = 1011
** ---其他问题:
if (x != a) { ret |= ROW; }
| =运算符在做什么?从我读到的,| =是OR,但我不太明白这句话是做什么的。**
if(x!= a)(希望这对你来说很明显......如果变量x不等于变量a)
ret |= ROW;
equates to
ret = ret | ROW;
表示二进制OR与ROW
有关AND和OR操作完成的示例,您应该对二进制逻辑有一个很好的理解。
检查维基百科的真值表......即
答案 9 :(得分:0)
我假设你的意思是char a ='3';对于第一行代码(否则你得到一个相当奇怪的答案)。基本原理是数字的ASCII码是顺序的,即'0'= 48的代码,'1'的代码= 49,依此类推。减去“0”只是简单地从ASCII码转换为实际数字,例如'3' - '0'= 3,依此类推。请注意,这只有在你减去'0'的字符是实际数字时才有效 - 否则结果没什么意义。
一个。没有上下文,这段代码的“原因”是不可能的。至于它正在做什么,似乎if语句在指针 - &gt; intX的第i位未设置时评估为真,即该特定位为0.我相信&amp;运算符在〜运算符之前执行,因为〜运算符的优先级非常低。代码可以更好地利用括号使操作的预期顺序更清晰。在这种情况下,操作顺序可能无关紧要 - 我相信结果都是相同的。
湾这只是创建一个带有所有位的数字,除了位i设置为1.为位i创建掩码的一种方便方法是使用表达式(1&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; i&gt;。)
这种情况下的按位OR运算用于将ROW常量指定的位设置为1.如果未设置这些位,则设置它们;如果它们已经设定则没有效果。