无法理解 C 中按位运算器中的 showbit() 函数 [已关闭]

can't understand showbit() function in bitwise operatrers in C [closed]

提问人:Nitin Bhartiya 提问时间:7/31/2022 最后编辑:John BollingerNitin Bhartiya 更新时间:7/31/2022 访问量:96

问:


想改进这个问题吗?更新问题,使其仅通过编辑这篇文章来关注一个问题。

去年关闭。

/* Print binary equivalent of characters using showbits( ) function */

#include <stdio.h>

void showbits(unsigned char);
    
int main() {
    unsigned char num;
    
    for (num = 0; num <= 5; num++) {
        printf("\nDecimal %d is same as binary ", num);
        showbits(num);
    }

    return 0;
}

void showbits(unsigned char n) {
    int i;
    unsigned char j, k, andmask;
    
    for (i = 7; i >= 0; i--) {
        j = i;
        andmask = 1 << j;
        k = n & andmask;
        k == 0 ? printf("0") : printf("1");
    }
}

分配的样本编号:0,1,2,3,4 ...num

有人可以详细解释一下发生了什么吗?,这是一个数字,例如 2,如何成为具有 的同一运算符的操作数,例如 10000000,因为 2 是 1 位值,而 100000000 是多位值?k = n & andmaskn&andmask

还有为什么是用于而不是?charnint

c 二进制 十进制 按位 和运算符

评论

0赞 Vlad from Moscow 7/31/2022
询问函数的作者。
0赞 qrsngky 7/31/2022
2 is 1 digit value以十进制表示。它(至少)是二进制的 2 位值,但您始终可以在它前面添加更多 s,而无需更改其数值,就像二进制中仍然是十进制的 2 一样100000010
0赞 qrsngky 7/31/2022
的大小为 1 字节。 大于 1 个字节。如果您只使用 0 到 5 之间的数字,那么 1 个字节就足够了。charint
0赞 qrsngky 7/31/2022
In 中最左边的位决定了结果,因为输出中的所有其他位都必须变为 0。如果最左边的位是 0,那么结果 (k) 就是 0。然后可以根据这个条件打印“0”;另一方面,如果最左边的位是 1,则为非零,因此打印“1”。然后,要判断第二位是否为 0,请使用 .然后将掩码更改为 、 等,以及 k 是否为 0。n & 10000000 (binary)n00000000 (binary)kn & 01000000 (binary)00100000 (binary)00010000 (binary)00001000 (binary)

答:

-1赞 Thibault BREZILLON 7/31/2022 #1

乍一看,此函数似乎以二进制表示形式打印 8 位值(0 和 1)。它创建一个掩码,用于隔离 char 值的每个位(将所有其他位设置为 0),如果掩码值为 0,则打印“0”,否则打印“1”。 之所以在此处使用,是因为该函数旨在打印 8 位值的二进制表示形式。如果在此处使用,则只会正确打印 [0-255] 范围内的值。 我不明白你对 1 位值和多位数值的看法。charint

评论

0赞 Nitin Bhartiya 7/31/2022
我的意思是要进行真值比较,您需要 2 个值,例如 1 和 1 将是 1,1 和 0 将是 0,但这里有 2 和 10000000 .你怎么能将 2 和 10000000 进行比较?
0赞 qrsngky 7/31/2022
@NitinBhartiya“2”甚至不是一个有效的二进制数字。它是二进制(8 位)格式。00000010
0赞 Nitin Bhartiya 7/31/2022
所以 2 会自动转换为 00000010,那么使用 showbit() 有什么意义,我不能在没有 showbit() 的情况下直接将这个 2 的二进制打印到屏幕上吗?
0赞 John Bollinger 7/31/2022
@NitinBhartiya,I/O 始终涉及内部和外部表示之间的转换。有时它们是相同的,但通常是不同的。你需要,因为 C 没有定义一种内置的方式来生成二进制外部表示。但是,如果您想转换为八进制或十六进制,那么您可以完全使用 和 来完成。showbit()scanfprintf
2赞 John Bode 7/31/2022 #2

让我们来看看它。

假设是 。的二进制表示形式是 。n2200000010

第一次通过循环等于 。声明j7

andmask = 1 << j;

取 的二进制表示,即 ,并将其向左移动 7 位,得到 ,赋值为 。10000000110000000andmask

声明

k = n & andmask;

对 和 执行按位 AND 运算:nandmask

  00000010
& 10000000
  --------
  00000000

并将结果分配给 。然后,如果它打印一个“0”,否则它打印一个“1”。kk0

所以,每次通过循环,它基本上都在做

j   andmask          n     result    output
-  --------   --------   --------    ------
7  10000000 & 00000010   00000000       "0"
6  01000000 & 00000010   00000000       "0"
5  00100000 & 00000010   00000000       "0"
4  00010000 & 00000010   00000000       "0"
3  00001000 & 00000010   00000000       "0"
2  00000100 & 00000010   00000000       "0"
1  00000010 & 00000010   00000010       "1"    
0  00000001 & 00000010   00000000       "0"

因此,输出为“00000010”。

因此,该函数正在打印出其输入值的二进制表示形式。他们使用而不是保持输出易于阅读(8 位而不是 16 位或 32 位)。showbitsunsigned charint

此代码的一些问题:

  • 它假设始终为 8 位宽;虽然通常是这种情况,但它可以(并且从历史上看)比这更广泛。为了安全起见,它应该使用中定义的宏:unsigned charCHAR_BITlimits.h
    #include <limits.h>
    ...
    for ( i = CHAR_BIT - 1; i >= 0; i++ )
    {
      ...
    }
  • ?:不是控制结构,不应用于替换 - 会更恰当地写成 That tell to output a if is non-zero,否则。if-else
    printf( "%c", k ? '1' : '0' );
    
    printf'1'k'0'

评论

0赞 Nitin Bhartiya 7/31/2022
感谢您的详细解释。只是另一个愚蠢的问题:所以 2 会自动转换为 00000010,那么使用 showbit() 有什么意义,我不能在没有 showbit() 的情况下直接将这个 2 的二进制文件打印到屏幕上吗?
0赞 qrsngky 7/31/2022
@NitinBhartiya printf 不会自动使用这种表示形式。请参阅 stackoverflow.com/questions/111928/...
1赞 John Bode 7/31/2022
@NitinBhartiya- 因为 C 没有二进制输出的转换说明符。它具有十六进制和八进制输出的转换说明符,但不是二进制。我们通常不显示二进制,因为它很难阅读 - 并且比 更容易阅读。printf1fb60176660001111110110110
0赞 John Bode 7/31/2022
并且不会“转换为” - 它在内部表示为 .所有值在内部都表示为二进制。20000001000000010
0赞 John Bollinger 7/31/2022 #3

有人可以详细解释一下发生了什么吗?n 是一个数字,例如 2,如何成为具有 的相同运算符的操作数,例如 10000000,因为 2 是 1 位值,而 100000000 是多位值?k = n & andmask&andmask

数字中的位数是该数字的特定表示形式的特征。在所呈现的代码的上下文中,您实际上似乎自己使用了两种不同的表示形式:

  • “2”似乎以 (i) 为基数 10,(ii) 没有前导零。

另一方面,我采取

  • “10000000”,以 (i) 为基数 2,(ii) 不带前导零。

在这种表示组合中,您关于数字数的主张是正确的,但不是特别有趣。假设我们考虑可比较的表示。例如,如果我们以 256 为基数表示两个数字呢?这两个数字在该基数中都有个位数表示。

这两个数字在基数 256 中也具有任意长度的多位数表示,通过在个位数表示之前加上任意数量的前导零而形成。当然,在任何基地都是如此。带有前导零的表示在人类交流中并不常见,但它们在计算机中是常规的,因为计算机最自然地使用固定宽度的数字表示。

对于按位和 () 来说,重要的是操作数的 base-2 表示形式,即 C 内置算术类型之一的宽度。根据 C 的规则,如有必要,任何算术运算符的操作数都会转换为通用数值类型。它们彼此具有相同数量的二进制数字(位),其中一些通常是前导零。正如我推断您所理解的,运算符通过组合来自这些 base-2 表示的相应位来计算结果,以确定结果的位。&&

也就是说,组合的位是

(leading zeroes)10000000 & (leading zeroes)00000010

还有为什么是用于而不是?charnint

它是 ,不是 ,它用于 和 。这是开发人员的选择。 可以改为,该函数将为原始数据类型 () 中可表示的所有输入生成相同的输出。unsigned charcharnandmasknintshowbits()unsigned char

评论

0赞 Nitin Bhartiya 7/31/2022
谢谢你在我的问题中付出了这么多努力,还有一个问题:由于 2 会在使用 & 运算符之前自动从十进制转换为二进制,有没有办法跳过 showbit() 函数,只通过格式说明符打印二进制形式?
0赞 John Bollinger 7/31/2022
@NitinBhartiya,正如我在另一条评论中所写的那样,不,你不能。至少,不是在标准 C 中。更准确地说,规范没有定义用于直接输出二进制表示的格式说明符。您可以选择八进制、十进制和十六进制。printf