admin管理员组

文章数量:1794759

操作符细节补充

在补充细节之前,先介绍一下原码反码补码(正数的三码相同)

在三码中,最高位就是符号位,即0是正数,1是负数。

计算机中存储整数的方式是将数转化为二进制,存的是数的补码

比如-6(一个整型4个字节),它的原码就是100000000000000000000110

-6的反码就是111111111111111111111001,可知反码是原码除了符号位不变,其他位进行取反得到。

-6的补码是111111111111111111111010,可知补码是原码加个1,其他不变的得到的。

计算机打印的时候是按照原码打印的,所以负数在打印前是先转化为原码的。

补充:移位操作符

移位操作符分为左移和右移操作符。

使用右移操作符的时候需要注意的是右移是算术移位还是逻辑移位。

算术移位和逻辑移位的区别在于

逻辑右移是 右边丢弃 左边补0;算术右移是右边丢弃,左边补原符号位

那么现在主流是算术右移还是逻辑右移呢?检验方法很简单,用-1就检验出来了

代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>
int main()
{
	int a = -1;//三码,存补码
	int b = a >> 1;
	printf("%d", b);
	return 0;
}

如果是逻辑右移,那么结果是正数,如果是算术右移,那么结果是-1。

显然,目前主流的是算术右移。

那么左移呢?

左移其实就挺简单了,只有左边丢弃,右边补0。

可以注意到,右移是2的n次方的效果,左移是*2n的效果。


补充:位操作符

位操作符只能操作正数

&叫做按位与,即是将两个数转化为二进制位,对应的二进制位有0则为0,全是1才是1;

|叫做按位或,同理,有1则1,全0才是0;

^叫做按位异或,这个就不同理了,这个规则是都不相同就是1,都相同就是0; (可以结合0为假,1为真记忆)

那么结合具体题目操作

不设临时变量交换两个数的值

这道题第一种方法就是加减法,如图:

代码语言:javascript代码运行次数:0运行复制
int main()
{
	int a = 3;
	int b = 5;
	a = a + b;
	b = a - b;
	a = a - b;
	return 0;
}

现在用按位操作符做

代码语言:javascript代码运行次数:0运行复制
int main()
{
	int a = 3;
	int b = 6;
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("%d %d", a, b);
	return 0;
}

其实这串代码可读性比较差,所以看看就行了。

那么换一道题可读性比较强的,

求一个数二进制里面有多少个1

这道题的思路不是第一时间想如何把数转化为二进制数,因为计算机已经帮你转化了

那么思路应该是结合上述所讲的移位操作符,一直用该数的最后一位和1进行按位与,如果都是1,那么指定一个数相加。

代码语言:javascript代码运行次数:0运行复制
//求一个整数存储在内存中的二进制中1的个数。
int main()
{
	int num = 0;
	int count = 0;
	scanf("%d", &num);
	/*while (num)
	{
		if (num % 2 == 1)
			count++;
		num = num / 2;
	}*/
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if (1 == ((num >> i) & 1))
			count++;
	}
	printf("%d", count);
	return 0;
}

可以看到,中间的while循环是被注释掉了,因为一个数极有可能二进制含有0,while循环就会停止。

为什么i<32呢?因为整型,32个比特位。

代码语言:javascript代码运行次数:0运行复制
int main()
{
    int num = 0;
    int count = 0;
    scanf("%d", &num);
    while (num)
    {
        num = num & (num - 1);
        count++;
    }
    printf("%d\n", count);
    return 0;
}

为大家提供另一种方法,有兴趣可以下来琢磨,别问,问就是编者觉得这串代码太厉害,无法介绍。


补充:逗号表达式

就是由逗号隔开的多个表达式,从左向右依执行,整个表达式的结果是最后一个表达式的结果

注意,是要执行的!

代码语言:javascript代码运行次数:0运行复制
int main()
{
	int a = 0;
	int b = 1;
	int c = (a > b, a = b + 10, a, b = a + 1);
	printf("%d", c);
	return 0;
}

执行顺序:a>b 无结果 a= b +10结果是a=11,a,无结果,b=a+1,结果是b=12

所以代码的最后结果是c=12;


补充:下标引用

代码语言:javascript代码运行次数:0运行复制
int main()
{
	int arr[10] = { 0 };
	arr[4] = 10;
	return 0;
}

[ ]有两个操作数,一个是arr 一个是4


补充:.操作符和->操作符

这两个是结构体中的操作符,所以先简单创造一个结构体

代码语言:javascript代码运行次数:0运行复制
struct stu
{
	//成员变量
	char name[20];
	int age;
	char id[20];
};
int main()
{
	int a = 10;
	struct stu s1 = {"自由",18,"230702140312"};
	struct stu* ps = &s1;
	printf("%s\n", ps->name);
	printf("%d\n", ps->age);
	printf("%s\n", ps->id);
	printf("\v");
	printf("%s\n", (*ps).name);
	printf("%d\n", (*ps).age);
	printf("%s\n", (*ps).id);
	printf("\v");
	printf("%s\n", s1.name);
	printf("%d\n", s1.age);
	printf("%s\n", s1.id);
	return 0;
}

创建的结构体是s1,成员变量有name age id,那么现在想要通过借助操作符打印结构体的成员变量有三种方法

1 通过点操作符  .操作符的左边是结构体,右边是成员变量,一般是使用形式是

结构体.成员变量 如

代码语言:javascript代码运行次数:0运行复制
	printf("%s\n", s1.name);
	printf("%d\n", s1.age);
	printf("%s\n", s1.id);

2 利用指针,但仍然使用.操作符,左边对指针变量进行解引用操作符,右边是成员变量

代码语言:javascript代码运行次数:0运行复制
	printf("%s\n", (*ps).name);
	printf("%d\n", (*ps).age);
	printf("%s\n", (*ps).id);

3 利用->操作符,使用形式是 左边是指针变量,右边是成员变量

代码语言:javascript代码运行次数:0运行复制
	printf("%s\n", ps->name);
	printf("%d\n", ps->age);
	printf("%s\n", ps->id);

补充:隐式类型转换·整型提升

什么是整型提升?

C语言中整型算术运算总是至少以缺省整型类型的精度来进行的 为了获得这个精度,表达式中的字符和短整型操作数在使用前被转换为普通整型,称为整型提升

注意几个点: 1 整型提升是按照数据变量的符号位进行提升的 2 无符号数高位直接补0 3 只有算术转化才存在整型提升

那么为什么C语言中存在隐式转化呢? 这是因为通用cpu难以实现两个8bit位的数直接相加。

文字的解释可能没有那么直观,现在结合代码进行解释

代码语言:javascript代码运行次数:0运行复制
int main()
{
    char a = 3;
    char b = 127;
    char c = a + b;
    printf("%d",c);
    return 0;
}

可能会认为结果是130,那么看看?

欸对吧,不是130,看,注释里面有截断两字,ok编者现在对其进行解读。

 整型提升后是4个字节位, 缺省整型类型即截断为8个比特位

比如3的二进制位是011,那么在计算机中是0000000000000000(截断)00000011,

同理,对127进行截断,是01111111,相加之后是10000010

那么c就是进行整型提升后就是111111111111111110000010

为什么是全是1?因为整型提升是根据数据变量的符号位进行整型提升的,所以c的原码就是

1000000000000000010000010

那么打印出来就是-126。

截断的定义是在原数据某位开始直接按照所需数据类型大小拿走所需数据。

比如一个数的二进制位在相加之后是1011111111(前面进行了省略),那么在整型提升后,它的结果是-1,话不多说,试验

整型提升例子

代码语言:javascript代码运行次数:0运行复制
//整型提升·示例1
int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	//printf("%d", a);
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	return 0;
}

说明char和short类型被截断

代码语言:javascript代码运行次数:0运行复制
//整型提升·示例2
int main()
{
	char c = 1;
	printf("%u\n", sizeof(c));
	printf("%u\n", sizeof(+c));
	printf("%u\n", sizeof(!c));//布尔类型
	return 0;
}

+c即对其进行了整型提升,因为+是算术操作符

!c因为是布尔类型的所以结果也是1

感谢阅读!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2024-08-13,如有侵权请联系 cloudcommunity@tencent 删除int变量二进制计算机数据

本文标签: 操作符细节补充