【问题标题】:Some random C questions (ascii magic and bitwise operators)一些随机的 C 问题(ascii 魔术和位运算符)
【发布时间】:2010-10-15 07:07:16
【问题描述】:

我正在努力学习 C 编程,我正在研究一些源代码,有些东西我不明白,尤其是关于位运算符。我阅读了一些关于这方面的网站,对它们的作用有所了解,但是当我回头查看这些代码时,我无法理解它们为什么以及如何使用它们。

我的第一个问题与位运算符无关,而是一些 ascii 魔法:

  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 个问题。它有两个优点: * 下面的一些答案只回答了其中一个问题。如果您分别提交它们,将很清楚正在回答哪个问题。 * 更多问题 ==> 更多支持 :)

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


【解决方案1】:

这会产生垃圾:

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-&gt;intX01101010,那么 ~pointer-&gt;intX 将是 10010101。 (请注意,自始至终,我都在说明一个字节的内容。如果它是一个 32 位整数,我必须写 32 位 1 和 0)。

& 运算符通过分别处理每个位将两个数字组合成一个数字。如果两个输入位都为 1,则结果位仅为 1。因此,如果左侧为 00101001,右侧为 00001011,则结果将为 00001001

最后,&lt;&lt; 表示左移。如果你从 00000001 开始,然后将它左移三位,你将得到 00001000。所以表达式 (1

综合起来,它会测试i 位是否在pointer-&gt;intX 中关闭(零)。

所以你也许能够弄清楚~(1 &lt;&lt; i) 做了什么。如果i4,则括号中的内容将是00010000,因此整个内容将是11101111

ret |= ROW;

那个相当于:

ret = ret | ROW;

| 运算符类似于&amp;,只是如果任一输入位为1,则结果位为1。所以如果ret00100000 并且ROW00000010,那么结果将是00100010

【讨论】:

  • 它还会检查是否每隔一个位为 0。
  • @tstenner - 你指的是哪一部分?
  • +1 得到了很好的答案。我认为这里有一个小错字:“如果我是 5,那东西..” s,5,4,g
  • +1 表示不会自动假设 ASCII。 '0'...'9' 关系由 C 保证,而 ASCII 则不然。
【解决方案2】:

ret |= ROW;

等价于

ret = ret | ROW;

【讨论】:

    【解决方案3】:

    对于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
    

    【讨论】:

      【解决方案4】:

      我想你可能有一个错字,意思是:

      char a = '3';
      

      这样做的原因是所有的数字都是按顺序排列的,“0”是第一个。显然,'0' - '0' = 0。'1' - '0' = 1,因为 '1' 的字符值比 '0' 的字符值大 1。等等。

      【讨论】:

        【解决方案5】:

        1) char 实际上只是一个 8 位整数。 '0' == 48,以及这意味着什么。

        2) (~(pointer->intX) & (1

        3) |是按位或。它获取两个操作数中的每个位并执行逻辑或,如果任一操作数设置了该位,则产生一个结果,其中设置了每个位。 0b11000000 | 0b00000011 == 0b11000011。 |= 是一个赋值运算符,同理 a+=b 表示 a=a+b,a|=b 表示 a=a|b。

        在某些情况下不使用位运算符可以使事情更容易阅读,但如果没有强大的编译器优化,它通常也会使您的代码显着变慢。

        【讨论】:

        • 请记住,C 并不强制要求 '0' == 48,尽管它在 ASCII 中是这样的。 C 要求数字字符按从“0”到“9”的连续顺序。
        • 一个很好的观点。让我知道 EBCDIC 何时重新流行 :)
        【解决方案6】:

        您引用的减法技巧有效,因为 ASCII 数字按升序排列,从零开始。因此,如果 ASCII '0' 是 48 的值(确实如此),那么 '1' 的值是 49,'2' 是 50,等等。因此 ASCII('1') - ASCII('0') = 49 - 48 = 1。

        就位运算符而言,它们允许您对变量执行位级操作。

        让我们分解你的例子:

        (1 &lt;&lt; i) -- 将常数 1 左移 i 位。因此,如果 i=0,则结果为十进制 1。如果 i = 1,则将第 1 位向左移动,用零回填,产生二进制 0010,或十进制 2。如果 i = 2,则将第 2 位移动到左,用零回填,产生二进制 0100 或十进制 4 等。

        ~pointer-&gt;intX -- 这是取指针的 intX 成员的值并将其位反转,将所有零设置为 1,反之亦然。

        &amp; -- & 运算符进行按位与比较。如果表达式的左侧和右侧均为 1,则此结果将为 1,否则为 0。

        所以如果pointer-&gt;intX在右边第i个位置有一个0位,测试就会成功。

        另外,|= 表示进行按位或比较并将结果分配给表达式的左侧。对于相应的左侧或右侧位为 1 的每个位,按位或的结果为 1,

        【讨论】:

          【解决方案7】:

          单引号用于表示使用单个字符。因此,'0' 是字符 '0',其 ASCII 码为 48。 3-'0'=3-48

          '1 ~pointer->intX 否定字段 intX,因此当 intX 的所有位都没有设置时,逻辑 AND 返回一个真值(非 0)。

          【讨论】:

            【解决方案8】:
            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

            在这种情况下,我不知道你为什么要反转指针的位..

            在第二次比较中,x |= y 与 x = x | 相同。是的

            【讨论】:

            • -> 的优先级高于~,你可以读成~(pointer->intX)
            【解决方案9】:
            1. 我假设您的意思是 char a='3';对于第一行代码(否则你会得到一个相当奇怪的答案)。基本原则是数字的ASCII码是连续的,即'0'=48的代码,'1'=49的代码,等等。减去“0”只是将 ASCII 码转换为实际数字,例如'3' - '0' = 3,依此类推。请注意,这仅在您从中减去“0”的字符是实际数字时才有效 - 否则结果将毫无意义。

            2. 一个。如果没有上下文,就无法说出这段代码的“为什么”。至于它在做什么,当指针->intX 的位 i 未设置时,if 语句的计算结果似乎为真,即该特定位为 0。我相信 & 运算符在 ~ 运算符之前执行,因为 ~运算符的优先级很低。该代码可以更好地使用括号来使预期的操作顺序更清晰。在这种情况下,操作的顺序可能并不重要——我相信结果是一样的。

              b.这只是创建一个除第 i 位之外的所有位都设置为 1 的数字。为第 i 位创建掩码的一种简便方法是使用表达式 (1

            3. 本例中的按位或运算用于将ROW常量指定的位设置为1。如果这些位没有设置,则设置它们;如果它们已经设置,则无效。

            【讨论】:

              【解决方案10】:

              1) 有人可以向我解释以下代码是如何工作的吗?字符 a = 3; int x = a - '0'; 我知道这样做是为了将 char 转换为 int,但是我不明白它背后的逻辑。为什么/如何工作?

              当然。变量 a 是 char 类型,并且通过在 0 周围加上单引号导致 C 也将其视为 char。最后,整个语句被自动类型转换为其等效整数,因为 x 被定义为整数。

              2) 现在,关于按位运算符,我觉得这里真的很迷茫。 --- 这段代码是做什么的? if (~pointer->intX & (1

              (~pointer->intX & (1 << i)) is saying:
              

              对 intX 求反,并将其与左移 i 位的 1 相与

              所以,如果 intX = 1011,并且 i = 2,则您得到的结果等于

              (0100 & 0100) 
              
              -negate 1011 = 0100
              
              -(1 << 2) = 0100
              
              0100 & 0100 = 1 :)
              

              然后,如果 AND 操作返回 1(在我的示例中,它确实如此) { C++; n = 我; }

              因此,将 c 加 1,并将变量 n 设置为 i

              与此行相同:row.data = ~(1

              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 ret 与 ROW

              对于 AND 和 OR 操作完成的确切示例,您应该对二进制逻辑有相当的了解。

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

              Bitwise operations

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-01-19
                • 1970-01-01
                • 1970-01-01
                • 2012-03-21
                • 1970-01-01
                • 2013-04-30
                • 2023-03-23
                相关资源
                最近更新 更多