C语言:操作符(下)

目录

单目操作符(sizeof与数组)

逻辑操作符

条件操作符

表达式求值

1).整型提升

整型提升的过程

2).算术转换

3).操作符的属性

单目操作符(sizeof与数组)

下面有一段代码:

void test1(int* arr)
{
	printf("%zd\n", sizeof(arr));
}
void test2(char* ch)
{
	printf("%zd\n", sizeof(ch));
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%zd\n", sizeof(arr));
	printf("%zd\n", sizeof(ch));
	test1(arr);
	test2(ch);
	return 0;
}

 打印结果为

 32位表示CPU能放下最大2^32(字节)的数值

 64位表示CPU能放下最大2^64(字节)的数值

数组传参,形参可以写成数组,也可以写成指针,但本质都是数组首元素地址

逻辑操作符

&&      并且

||         或

逻辑表达式返回值为 1 / 0 ,真或假

看这样一段代码

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
	return 0;
}

打印结果分别为1  2  3  4

由于赋值操作符=优先级很低,所以先执行右边表达式。a++为后置++,先使用,但a=0为假,右边表达式一定为假,所以b,d并未进行操作,故结果为1 2 3 4 ,则逻辑表达式返回0,即i=0

同样的,下面这段代码

int main()
{
	int i = 0, a = 1, b = 2, c = 3, d = 4;
	i = a++ || ++b || d++;
	printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
	return 0;
}

打印结果为2  2  3  4。a=1为真,则该表达式一定为真,所以b,d不进行操作

条件操作符

exp1  ?exp2  :exp3

若exp1成立,则执行exp2,否则执行exp3

表达式求值

1).整型提升

C语言中整型算术运算总是至少以缺省(默认)整型类型的精度来进行的

为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升

整型提升的意义

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度

因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。 通用CPU(general-purposeCPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)

所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算

a 和 b 的值先被提升为普通整型,然后再执行加法运算

整型提升的过程

1. 有符号整数提升是按照变量的数据类型的符号位来提升的

2. 无符号整数提升,高位补0

char  a  =  3;

3的二进制序列为

00000000000000000000000000000011

截断(char占8个字节)

00000011  —>  a

char  b  =  127;

127的二进制

00000000000000000000000001111111

截断

01111111  —>  b

char  c  =  a  +  b;

00000011  a

01111111  b

进行运算,要整型提升高位补0

00000000000000000000000000000011  a

00000000000000000000000001111111  b

相加

00000000000000000000000010000010  c

截断

10000010  —>  c

printf(" %d\n " ,  c);

%d  是打印十进制的整数

整型提升,高位补1

11111111111111111111111110000010  —  补码

11111111111111111111111110000011

10000000000000000000000011111110  —  原码

即-126

来看一段代码

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被打印

0xb6为十六进制数字(0x表示b6是十六进制)

0xb6的二进制序列为 

00000000000000000000000010110110

截断

10110110 

整型提升,高位补1

11111111111111111111111110110110  ——>  a

显然 00000000000000000000000010110110  ! =  11111111111111111111111110110110

故a不打印 

同理,b 也不打印

c为整形类型,不进行整型提升,故打印

再看这样一个运行结果

 (%u打印无符号整数)

+c ,-c 使c发生整型提升,int类型占4个字节

2).算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行,下面的层次体系称为寻常算术转换

1  long double

2  double

3  float

4  unsigned long int

5  long int

6  unsigned int

7  int 

如果某个操作数的类型在上面这个列表中排名靠后,那么首先要转换为另外一个操作数的类型后执行运算

3).操作符的属性

1  操作符的优先级

2  操作符的结合性

优先级,即决定谁先算,谁后算

结合性,即优先级相同时,决定左结合(从左往右算)还是右结合(从右往左算)

大部分运算符是左结合,少部分为右结合

参考: ​​​​​​https://zh.cppreference.com/w/c/language/operator_precedence

常用的优先级顺序

• 圆括号( () )

• 自增运算符( ++ ),自减运算符( -- )

• 单目运算符( + 和 - )

• 乘法( * ),除法( / )

• 加法( + ),减法( - )

• 关系运算符( < 、 > 等)

• 赋值运算符( = ) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值