一些随机的C问题(ascii魔术和按位运算符)

时间:2009-03-24 19:17:21

标签: c++ c bit-manipulation bitwise-operators

我正在尝试学习C编程,我正在研究一些源代码,有一些我不理解的东西,特别是关于Bitwise运算符。我在这上面阅读了一些网站,我对他们的工作有了一个了解,但当我回过头来查看这些代码时,我无法理解他们使用的原因和方式。

我的第一个问题与按位运算符无关,而是与ascii magic有关:

  1. 有人可以向我解释以下代码的工作原理吗?

    char a = 3;
    int x = a - '0';
    

    我理解这是将char转换为int,但我不理解它背后的逻辑。为什么/如何运作?

  2. 现在,关于按位运算符,我觉得我真的迷失了。

    • 这段代码做了什么?

      if (~pointer->intX & (1 << i)) { c++; n = i; }
      

      我在某处读到了〜反转位,但是我没有看到这句话是做什么的,为什么会这样做。

      与此行相同:

      row.data = ~(1 << i);
      
    • 其他问题:

      if (x != a)
        {
          ret |= ROW;
        }
      

      | =运算符到底在做什么?从我读到的,| =是OR,但我不太明白这句话是做什么的。

      有没有办法重写这段代码,以便更容易理解,以便它不使用这个按位运算符?我发现他们很容易理解,所以希望有人能指出我正确的方向,了解他们如何更好地工作!


  3. 我现在对按位运算符有了更好的理解,现在整个代码更有意义。

    最后一件事:似乎没有人回应是否有一种“更清洁”的方式来重写这段代码的方式更容易理解,也许不是“bitlevel”。有什么想法吗?

10 个答案:

答案 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->intX01101010,则~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)的作用。如果i4,则括号中的内容为00010000,因此整个内容为11101111

ret |= ROW;

那个相当于:

ret = ret | ROW;

|运算符与&类似,不同之处在于,如果任一输入位为1,则结果位为1。因此,如果ret00100000ROW00000010,则结果为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操作完成的示例,您应该对二进制逻辑有一个很好的理解。

检查维基百科的真值表......即

Bitwise operations

答案 9 :(得分:0)

  1. 我假设你的意思是char a ='3';对于第一行代码(否则你得到一个相当奇怪的答案)。基本原理是数字的ASCII码是顺序的,即'0'= 48的代码,'1'的代码= 49,依此类推。减去“0”只是简单地从ASCII码转换为实际数字,例如'3' - '0'= 3,依此类推。请注意,这只有在你减去'0'的字符是实际数字时才有效 - 否则结果没什么意义。

  2. 一个。没有上下文,这段代码的“原因”是不可能的。至于它正在做什么,似乎if语句在指针 - &gt; intX的第i位未设置时评估为真,即该特定位为0.我相信&amp;运算符在〜运算符之前执行,因为〜运算符的优先级非常低。代码可以更好地利用括号使操作的预期顺序更清晰。在这种情况下,操作顺序可能无关紧要 - 我相信结果都是相同的。

    湾这只是创建一个带有所有位的数字,除了位i设置为1.为位i创建掩码的一种方便方法是使用表达式(1&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; i&gt;。)

  3. 这种情况下的按位OR运算用于将ROW常量指定的位设置为1.如果未设置这些位,则设置它们;如果它们已经设定则没有效果。