C语言的二进制及其相关操作符

一、二进制数

日常生活中我们所接触的数字都是10进制,对于其他进制的数字可能听过但不一定真正的清楚并了解,比如除了10进制,还有2进制,8进制,16进制。其实由称呼就能知道的区别,比如10进制就是每十个数进一位,1 2 3 4 5...9->10,这样就是10进制,(生活中也有很多不同进制的数字,比如年月日中年和月的进制就是12进制,或者小时和分,分和秒的进制是60。)其他进制的数字也同样是一个道理。

9的各种进制形式
16进制:9    //10以上的数字分别用ABCDEF代替
8进制:11
2进制:1001
//16进制的数值之前写:0x 
//8进制的数值之前写:0 

二、原码 反码 补码

数字在内存中存储时是二进制数字。而一般将数据存放在内存中时存放的是补码。

原码:就是将数字转换成2进制数字的形式就是原码。

反码:将原码中的0换成1,1换成0就是反码。

补码:在反码的基础上+1就是补码。

内存中二进制数最左边的数字是符号位,0表示"正",1表示"负"。

三、位移操作符

位移操作符分为两种,分别是左移操作符“<<”和右移操作符“>>”,它们的作用是将二进制位的数相应的向左或向右挪移。

1.左移操作符

比如左移操作符使二进制数向左移动1位,那么最左边的数就被挤出去了,而右边也是同理,光说可能不太明白,没关系,我们看个图。

像这样就是一个为10的数字向左位移1位的样子了,通过代码是这样实现的:

#include <stdio.h>
int main()
{
    int a = 10;
    printf("%d\n", a);//10
    printf("%d\n", a << 1);//20
    return 0;
}

有没有发现什么?向左位移一次就让结果变成了2倍,这是巧合吗?让我们再试一次。

#include <stdio.h>
int main()
{
    int a = 10;
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        printf("%d\n", a << i);
    }
    return 0;
}

运行结果:

看来往左移动多少位,数字就会乘以相应次数的2。

注:它们都只能作用于整数!!!

2.右移操作符

和左移操作符基本一样,有一点不同的是:左移操作符是向右补位,没有正负之分,而右移操作符是向左补位,有正负之分,于是右移操作符有两种形式。

逻辑右移:左边用0补充,右边丢弃。

算术右移:左边用原来的符号位补充,右边丢弃。

还需要注意的是位移操作符不能移动负数位

四、位操作符

常见的位操作符有四种,它们分别为&,|,^,~。前两种大概大家早在之前学习分支和循环语句时就已经见过了,它们作用在整形数据中使用二进制表示的数据中的每一位。

  • &(与):同为1才为1,否则为0;
  • |(或):有1就为1;
  • ^(异或):不同为1,否则为0;
  • ~(非):按位取反,0变1,1变0;

或许通过文字这样来看,表达出的意思还不够清晰,让我们直接来上代码。

1.&(与)操作符

同为1才为1,否则为0;

int a = -5;
int b = 7;
printf("%d\n", a & b);

int型在32位机器上占四个字节,那么高位补零,让我们看一下-5和7的原码:

a->10000000000000000000000000000101

b->00000000000000000000000000000111

分别求出a和b的补码,先对原码取反,然后再对反码+1。

a->10000000000000000000000000000101
   11111111111111111111111111111010//求反
   11111111111111111111111111111011//+1,补码
b->00000000000000000000000000000111//正数的补码与反码相同
//&:同为1才为1,否则为0;
得 a&b为00000000000000000000000000000011//输出结果为3

运行结果展示:这就是&(与)位操作符啦。

2.|(或)操作符

有1就为1;

接下来我们看|(或)操作符,同样是用a与b的补码来进行计算

11111111111111111111111111111011//a补码
00000000000000000000000000000111//b反码
//|(或)操作符:有1就为1;
a|b->11111111111111111111111111111111//(还得取反+1变成原码才行)
   ->10000000000000000000000000000000
   ->10000000000000000000000000000001//输出-1

运行结果展示:

3.^(异或)操作符

不同为1,否则为0;

接下来我们看^(异或)操作符,同样是用a与b的补码来进行计算

11111111111111111111111111111011//a补码
00000000000000000000000000000111//b反码
//^(异或):不同为1,否则为0;
a^b->11111111111111111111111111111100//(还得取反+1变成原码才行)
   ->10000000000000000000000000000011
   ->10000000000000000000000000000100//输出-4

运行结果展示:

4.~(非)操作符

按位取反,0变1,1变0;

这个与前三种不太一样,就是字面意思的取反效果,我们换一个表达式来体现它的效果和作用。

printf("%d\n", ~0);
//00000000000000000000000000000000
//取反
//11111111111111111111111111111111(再取反+1)
//10000000000000000000000000000001(-1)
练习题:判断一个整数存储在内存中的二进制中1的个数

我们先思考一下,这题应该怎么样去做呢?因为我们之前做的计算题大部分都是十进制为基础来进行运算的,而在内存中的二进制数字对于我们来讲还是比较陌生的,但其实仔细想想,这样类似的题我们之前其实经常做的~

判断二进制数字中1的个数...其实这个和之前我们做过的,打印出一个数字的每一位数,是一个道理,打印出一个数字的每一位数,需要我们对这个数字的个位,十位,百位分别对10取余,然后再分别打印出来,是一个%10,/10,%10,/10的顺序。我们先来看一下如何打印出数字的每一位数。

#include <stdio.h>
void Print(int n)
{
    if (n > 9)
    {
        Print(n / 10);//这里运用到了递归函数,在下一篇文章我会为大家更详细的讲解
    }                 //进入后一直/10,直到只剩一个最高位数,然后从最高位,第二位,第三位...
                      //一直打印到最后一位
    printf("%d ", n % 10);
}
int main()
{
    int a;
    scanf("%d", &a);
    Print(a);
    return 0;
}

通过这样的方法就能够打印出一个数字的每一位数。

我们转变一下思路,那我们是否能用%2,/2,%2,/2...的方法将一个数字转换成二进制数字呢?

我们假设要将19转换为二进制数;
19 % 2 = 9......1;
19 / 2 = 9;
9 % 2 = 4......1;
9 / 2 = 4;
4 % 2 = 2......0;
4 / 2 = 2;
2 % 2 = 1......0;
2 / 2 = 1;
1 % 2 = 0......1;
1 / 2 = 0;

最后我们得到的二进制数字是10011(取余数从下往上读),对应的数字正好就是19,那么这次实验也验证了我们的想法,证明这是可行的,我们只需要用取余的方式将数字对应的二进制数字的每一位求出来,然后再算出一共有多少个1就可以了

#include <stdio.h>
int Print(int n)
{
    int num = 0;
    while (n)
    {
        if (n % 2 == 1)
        {
            num++;
        }
        n = n / 2;
    }
    return num;
}
int main()
{
    int a;
    scanf("%d", &a);
    int m = Print(a);
    printf("%d", m);
    return 0;
}

运行结果展示:

但其实这个代码只能适用于正数!比如-1进入,第一次循环-1/2直接等于0,输出0。但其实-1在内存当中的二进制是11111111111111111111111111111111(32个1)。)

那么最终我们得出这个代码只适用于部分情况,那到底什么做法才能让它适用于所有情况呢?我们再看刚才所举的数字19,它在内存中的形式是00000000000000000000000000010011,如果我们打破之前的思想,利用我们今天新接触的知识来进行思考...有了!&(与)操作符的作用是:同为1才为1,否则为0;那我们能不能做到对二进制的32位数挨个对1按位与运算符&(num & 1),检查出一个1,我们的计数数字num就+1,这样是否能求出二进制中1的个数呢?首先我们要先做到遍历32位数字,如果用我们刚刚学习到的位移操作符,位移31次就能做到全部遍历一遍了!思路有了,敲代码吧~

#include <stdio.h>
int Print(int n)
{
    int num = 0;
    int i = 0;
    int m = 0;
    for (i = 0; i < 32; i++)
    {
        if (((n >> i) & 1) == 1)
        {
            num++;
        }
    }
    return num;
}
int main()
{
    int a;
    scanf("%d", &a);
    int m = Print(a);
    printf("%d", m);
    return 0;
}

运行结果展示:

五、逗号表达式

顾名思义,就是逗号组成的表达式。用一个个逗号把好几个式子分别分隔开来,就是逗号表达式。

逗号表达式是以从左往右的顺序计算,最终的结果就是最右方表达式的结果。

int main()
{   
    int a = 0;
    int b = 7;
    int c = 2;
    int m=(++a, b = a + c, a = a + 3, a );
    printf("%d", m);
    return 0;
}

我们用这个代码为例,这就是一个逗号表达式,我们需要从左到右的顺序进行运算。首先++a,a变成1,b=a+c,使b变成了3,然后a又自增了3变成了4,最后表达式为a,a=4,则m=4,运行结果也就为4。

运行结果展示:

好了,那今天关于二进制及其相关操作符的知识就给大家分享到这里了,如果有讲的不好或者不对的地方还望指出,希望我能和大家一起共同进步,那我们下次见啦。

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
### 回答1: 在 C 语言中,可以使用 "%b" 格式化输出二进制数。例如: ``` int x = 5; printf("x in binary: %b", x); ``` 将会输出 "x in binary: 101"。 需要注意的是,"%b" 格式化输出是 C99 标准才支持的,如果在不支持 C99 的编译器中使用会产生编译错误。 ### 回答2: C语言中可以使用整数类型来表示和展示二进制数。在C语言中,二进制数以0b或0B开头,后面跟着二进制数的表示。 下面是几个示例: 1. 十进制转二进制: ```c int num = 10; printf("%d的二进制表示:0b%d\n", num, num); ``` 输出: ``` 10的二进制表示:0b1010 ``` 2. 二进制转十进制: ```c int binNum = 0b1010; printf("0b1010的十进制表示:%d\n", binNum); ``` 输出: ``` 0b1010的十进制表示:10 ``` 3. 二进制加法: ```c int a = 0b1010; int b = 0b1100; int result = a + b; printf("0b1010 + 0b1100 = 0b%d\n", result); ``` 输出: ``` 0b1010 + 0b1100 = 0b10110 ``` 通过使用整数类型和合适的格式化输出函数,我们可以方便地展示和操作二进制数。 ### 回答3: 在C语言中,我们可以使用整型数据类型来展示二进制数。C语言提供了几种不同的整型数据类型,如char、short、int和long等,它们在内存中以二进制的形式存储数据。 例如,我们可以使用int类型来展示二进制数。int类型通常使用32位(或64位)的二进制来表示一个整数。我们可以使用下面的方式将一个整数以二进制的形式展示出来: 1. 使用位运算操作符来逐个获取每一位的二进制值。可以使用右移运算符(>>)和按位与运算符(&)来实现。 2. 使用printf函数的格式控制符“%d”和“%x”来分别将整数以十进制和十六进制形式打印出来。可以通过修改格式控制符为“%b”(这是C语言中没有的格式控制符)来实现以二进制形式打印。 下面是一个示例代码,展示了如何将一个整数以二进制形式展示出来: ```c #include <stdio.h> void printBinary(int num) { int i; for (i = sizeof(int) * 8 - 1; i >= 0; i--) { printf("%d", (num >> i) & 1); } printf("\n"); } int main() { int num = 42; printf("十进制形式:%d\n", num); printf("十六进制形式:%x\n", num); printf("二进制形式:"); printBinary(num); return 0; } ``` 输出结果: ``` 十进制形式:42 十六进制形式:2a 二进制形式:00000000000000000000000000101010 ``` 通过上面的代码,我们可以看到一个整数在内存中的二进制表示形式。这种方法可以应用于任何整型数据类型,只需要相应地修改位运算和打印输出的操作即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值