C语言---- *** 作符

C语言---- *** 作符,第1张

C语言---- *** 作

目录

一.移位 *** 作符

二.位 *** 作符

三.sizeof *** 作符

四.结构体

五.表达式求值

1) 整型提升

 2)算术转换(隐式转换)

3) *** 作符的属性


一.移位 *** 作符

1.整数的二进制表示有三种形式:

原码,反码补码

2.正数的原码,反码,补码是相同的

负数的原码,反码,补码是要计算的

3.整数在内存中存储的是补码的二进制

4. a:5的补码00000000000000000000000000000101

    将该补码向左移动一位,左边丢去一位,右边补上一位0

    打印为补码

5.a:-5的原码10000000000000000000000000000101

         -5的反码111111111111111111111111111111111010

                补码111111111111111111111111111111111011 

<<1后的补码变为111111111111111111111111111111110110

                    反码111111111111111111111111111111110101

打印出的值为原码 10000000000000000000000000001010

6.原码,反码与补码

7.右移 

 

 a:5的补码00000000000000000000000000000101

  右移 *** 作符:

(1)算术右移:右边丢弃,左边补原符号位

(2)逻辑右移:右边丢弃,左边补0

a:-5的原码10000000000000000000000000000101

      -5的反码111111111111111111111111111111111010

             补码111111111111111111111111111111111011 

      >>1后的补码变为111111111111111111111111111111111101

                   反码111111111111111111111111111111111100

 打印出的值原码 10000000000000000000000000000011

>> 当前编译器,在右移采用算术右移

>>到底算术右移还是逻辑右移取决于编译器

8.警告

对于移位 *** 作符,不要移动负数,这个是标准未定义的

二.位 *** 作符

&
按二进制位与
如果两个相应的二进制位都为1,则该位的结果值为1,否则为0
|
按二进制位或
两个相应的二进制位中只要有一个为1,该位的结果值为1
^
按二进制位异或
若参加运算的两个二进制位值相同则为0,否则为1

a^a=0   0^a=a
~
按二进制取反
~是一元运算符,用来对一个二进制的补码数按位取反,即将0变1,将1

1.为什么while (~scanf("%d",&n));可以终止循环?

while (scanf("%d", &n) != EOF)
{
	.....
}
scanf()读取失败的时候,返回EOF
EOF---> -1
~(-1)=0

2.交换两个数的值 (仅整数可以使用)

 

	a = a ^ b;
	b = a ^ b ^ b;
	a = a ^ b ^ a;
三.sizeof *** 作符

1.sizeof不是函数

 2.sizeof求数组,求的是数组元素的类型*元素个数

int main()
{
	int arr[10] = { 0 };
	printf("%dn", sizeof(arr));
	return 0;
}

3.sizeof()内表达式不参与计算

int main()
{
	int a=10;
    short s=0;
	printf("%dn", sizeof(s=a+2));
    printf("%dn", sizeof(s));
	return 0;
}

2  0

test.c--->编译(求sizeof的结果,所以编译期间sizeof(s=a+2)变成了2)--->链接(s=a+2不存在了)       --->test.exe    

4.sizeof和函数

字符的地址仍然是48个字节,地址总是48个字节

void test1(int arr[])
{
	printf("%dn", sizeof(arr));
}
void test2(int ch[])
{
	printf("%dn", sizeof(ch));
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%dn", sizeof(arr));
	printf("%dn", sizeof(ch));
	test1(arr);
	test2(ch);
	return 0;
}
40 10 4 4
四.结构体
struct Stu
	{
		char name[20];
		int age;
		float score;
	};
	void print1(struct Stu ss)
	{
		printf("%s %d %fn", ss.name, ss.age, ss.score);
	}
	
	结构体变量.成员名
	
	void print2(struct Stu* ps)
	{
		printf("%s %d %fn", (*ps).name, (*ps).age, (*ps).score);
		printf("%s %d %fn", ps->name, ps->age, ps->score);
	}
	结构体指针->成员名
	
	int main()
	{
		struct Stu s = {"张三", 20, 90.5f};
		strcpy(s.name, "张三丰");
		scanf("%s", s.name);
		print1(s);
		print2(&s);
		return 0;
	}

  *(s.name)  = "张三丰"// err

s.name首字符的地址,解地址后只有一个字符

五.表达式求值 1) 整型提升

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

1.正数:高位补1   2.负数:高位补0   3.无符号数:高位补0

意义:表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的 *** 作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型 *** 作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算

int main()
{
	char c1 = 3;
	//00000000000000000000000000000011
	//00000011 - c1
	char c2 = 127;
	//00000000000000000000000001111111
	//01111111 - c2
	char c3 = c1 + c2;
	//00000000000000000000000000000011  -   c1
	//00000000000000000000000001111111  -   c2
	//00000000000000000000000010000010  -   c3
	//10000010 - c3
	//11111111111111111111111110000010  (-1)
	//11111111111111111111111110000001
	//10000000000000000000000001111110
	//-126
	printf("%dn", c3);
	return 0;
}
int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	return 0;
}
打印:c  //a和b发生了整型提升
int main()
{
	char c = 1;
	printf("%un", sizeof(c));//1
	printf("%un", sizeof(+c));//4
	printf("%un", sizeof(-c));//4
	return 0;
}
//在sizeof里发生运算,发生了整型提升后,就变为整型
 2)算术转换(隐式转换)

定义:如果某个 *** 作符的各个 *** 作数属于不同的类型,那么除非其中一个 *** 作数的转换为另一个 *** 作数的类型,否则 *** 作就无法进行。

看数据取值范围,最终是表达式中取值范围最大的那个类型

3) *** 作符的属性

复杂表达式的求值有三个影响的因素。
1. *** 作符的优先级
2. *** 作符的结合性
3. 是否控制求值顺序。 

从上到下优先级降低 

结合型N/A: 无结合性      L-R : 从左向右

一些问题表达式

a*b+c*d+e*f   (错误代码,无法确定唯一计算路径)

注释:代码1在计算的时候,由于*比+的优先级高,只能保证,*的计算是比+早,但是优先级并不能决定三个*哪一个比第一个+早执行。
c+--c  (错误)

注释:同上, *** 作符的优先级只能决定自减--的运算在+的运算的前面,但是我们并没有办法得知,+ *** 作符的左 *** 作数的获取在右 *** 作数之前还是之后求值,所以结果是不可预测的,是有歧义的。

总结:我们写出的表达式如果不能通过 *** 作符的属性确定唯一的计算路径,那这个表达式就是存在问题的

 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5713972.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存