c语言操作符

目录​​​​​​​

算术操作符

%

/

移位操作符

左移<<

右移>>

位操作符

按位与

按位或

按位异或

单目操作符

sizeof与数组

~

++/--

逗号表达式

下标引用,函数调用,结构成员

整型提升

算术转换

操作符属性


算术操作符

%

/

移位操作符

左移<<

右移>>

位操作符

按位与

按位或

按位异或

单目操作符

sizeof与数组

~

++/--

逗号表达式

下标引用,函数调用,结构成员

整型提升

算术转换

操作符属性


算术操作符

%

取模操作符的两个操作数必须为整数。

返回的是整除之后的余数。

模0或模负数无意义

int main()
{
	int a = 7 % 3.0;
	return 0;
}

/

两个操作数都为整数,执行整数除法。

而只要有浮点数执行的就是浮点数除法。

#include <stdio.h>
int main()
{
	float a = 100 / 24.0;
	float b = 100 / 24;
	printf("%f %f\n", a,b);
	return 0;
}

移位操作符

所谓移位,移的是二进制位

左移<<

规则:

左边抛弃,右边补0

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

右移>>

  1. 逻辑移位

左边用0填充,右边丢弃

  1. 算术移位

左边用原该值的符号位填充,右边丢弃

整数的二进制表示形式:

原码:直接根据数值写出的二进制序列就是原码

反码:原码符号位不变,其他位按位取反

补码:反码+1

负数存放在内存中,存放的是二进制的补码

正整数三码相同

-1

原码:1000000000000000000000000001

反码:11111111111111111111111111111110

补码:11111111111111111111111111111111

int main()
{
	int b = 0;
	int a = -1;
	b = a >> 1;
	printf("%d\n", b);
	return 0;
}

结果仍是-1,说明当前右移操作符使用的是算术右移

注意!!!

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

位操作符

位操作符操作数必须为整数

按位,按2进制位

按位与

&

2个都是1才是1,只要有0就是0

00000000000000000000000000000011

00000000000000000000000000000101

结果:

00000000000000000000000000000001

按位或

|

只要有1就是1,同时为0才是0

按位异或

^

相同为0相异为1

一道面试题:

交换2个int变量的值,不使用第三个变量

int main()
{
	int a = 3;
	int b = 5;
	printf("a=%d b=%d\n", a, b);
	a = a + b;
	b = a - b;
	a = a - b;
	printf("a=%d b=%d\n", a, b);

	return 0;
}

缺点:数值太大可能会溢出 毕竟只有32位

改进:

#include <stdio.h>
int main()
{
 int a = 3;
 int b = 5;
 printf("a = %d b = %d\n", a, b);
 a = a^b;
 b = a^b;
 a = a^b;
 printf("a = %d b = %d\n", a, b);
 return 0; }

a^a=0

0^a=a

a^b^b=a

b^a^b=a

练习:

求一个整数存储在内存中的二进制中1的个数。

001101

&

000001

=

000001

最后一位为1才是1

int main()
{
	int num = 10;
	int i = 0;
	int count = 0;//计数
	for (i = 0; i < 32; i++)
	{
		if (num & (1<<i))
			count++;
	}
	printf("二进制中1的个数 = %d\n", count);
	//10  00000000000000000000000000001010
	return 0;
}

单目操作符

sizeof与数组

求变量(类型)所占空间的大小

单位是字节

void test1(int arr[])	//此处arr[]是 int* arr
{
 printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
 printf("%d\n", sizeof(ch));//(4)
}
int main()
{
 int arr[10] = {0};
 char ch[10] = {0};
 printf("%d\n", sizeof(arr));//(1)
 printf("%d\n", sizeof(ch));//(3)
 test1(arr);
 test2(ch);
 return 0;
}

数组传参传的是首地址

指针的大小始终为4/8,与32位或64位平台有关

int main()
{
	short s = 5;
	int a = 10;
	printf("%d\n", sizeof(s = a + 2));
	printf("%d\n", s);

	return 0;
}

s的值和类型均为发生改变

sizeof括号中的表达式是不参与运算的

sizeof的运算是在编译时就开始计算的了

test.c-->test.exe(可执行文件)

编译-->链接-->运行

~

int main(){	int a = -1;	int b = ~a;	//10000000000000000000000000000001	原码	//11111111111111111111111111111110	反码	//11111111111111111111111111111111	补码	printf("%d\n", a);	printf("%d\n", b);	return 0;}

按位取反对内存中的补码进行按位取反

练习:

int main()
{
	int a = 13;
	//把a的二进制中的第5位置成1
	a = a | (1 << 4);
	//00000000000000000000000000001101
	// |
	//00000000000000000000000000010000
	// =
	//00000000000000000000000000011101
	// 
	//把a的二进制中的第5位置成0
	//00000000000000000000000000011101
	// &
	//11111111111111111111111111101111
	// =
	//00000000000000000000000000001101

	//00000000000000000000000000010000
	
	a = a & ~(1 << 4);
	printf("a=%d\n", a);
	return 0;
}

++/--

i++ 先用了再加

++i 先加了再用

int main()
{
    int i = 0,a = 0,b = 2,c = 3,d = 4;
    i = a++ && ++b && d++;
    //i = a++||++b||d++;
    printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
    return 0; }
//程序输出的结果是什么?

1 2 3 4

第一个表达式为0 后面的表达式就不再计算

int main()
{
    int i = 0,a = 1,b=2,c = 3,d = 4;
    i = a++ && ++b && d++;
    //i = a++||++b||d++;
    printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
    return 0; }
//程序输出的结果是什么?

2 3 3 5

int main()
{
	int i = 0, a = 1, b = 2, c = 3, d = 4;
	//i = a++ && ++b && d++;
	i = a++||++b||d++;
	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
	return 0;
}
//程序输出的结果是什么?

2 2 3 4

1为真,后面的表达式均不用计算

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	//i = a++ && ++b && d++;
	i = a++||++b||d++;
	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
	return 0;
}
//程序输出的结果是什么?

1 3 3 4

逗号表达式

逗号表达式,从左向右依次执行。

整个表达式的结果是最后一个表达式的结果。

a = get_val();
count_val(a);
while (a > 0) 
{
   		//业务处理
        a = get_val();
        count_val(a);
}
如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0) {
         //业务处理
}

下标引用,函数调用,结构成员

1.[]下标引用操作符

arr[9]

[]的2个操作数为arr和9

2.()

函数调用必须有函数调用操作符

有时还需要传参

#include <stdio.h>
 void test1()
 {
 printf("hehe\n");
 }
 void test2(const char *str)
 {
 printf("%s\n", str);
 }
 int main()
 {
 test1();  //操作数为test1        
 test2("hello bit.");	//操作数为test2,"hello bit."
 return 0;
 }

3.结构成员访问操作符

.

结构体变量.成员名

struct Book
{
	char name[20];
	char id[20];
	int price;
};
int main()
{
	struct Book b = { "c语言","c20201311",55 };
	printf("书名:%s\n", b.name);
	printf("书号:%s\n", b.id);
	printf("书价:%d\n", b.price);

	return 0;
}

->

struct Book
{
	char name[20];
	char id[20];
	int price;
};
int main()
{
	struct Book b = { "c语言","c20201311",55 };
	struct Book* pb = &b;
	printf("书名:%s\n", pb->name);
	printf("书号:%s\n", pb->id);
	printf("书价:%d\n", pb->price);
	return 0;
}

整型提升

有些表达式的操作数在求值的过程中可能需要转换为其他类型.

C的整型算术运算总是至少以缺省整型类型的精度来进行的.

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

整型提升意义:

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度

一般就是int的字节长度,同时也是CPU的通用寄存器的长度。

因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。

通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。

所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,

然后才能送入CPU去执行运算。

int main()
{
	char a = 3;
	//00000011
	//高位补充符号位 0
	//00000000000000000000000000000011
	char b = 127;
	//01111111
	//00000000000000000000000001111111
	//a和b都是char类型,都没有达到int大小,会发生整型提升
	char c = a + b;
	//00000000000000000000000010000010
	//10000010 -c
	//整型提升:
	//11111111111111111111111110000010 -补码
	//11111111111111111111111110000001 -反码
	//10000000000000000000000001111110 -原码
	//补码+1=反码 ~反码=原码
	//在内存中以补码形式存储,计算
	//打印出来的是原码的形式
	printf("%d\n", c);//-126
	return 0;
}

无符号整形提升,高位补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;
}
//a,b会进行整型提升,就不是原来的值了

只会输出c

int main()
{
 char c = 1;
 printf("%u\n", sizeof(c));
 printf("%u\n", sizeof(+c));
 printf("%u\n", sizeof(-c));
 return 0; 
}

输出结果 1 4 4

+c -c 进行运算时整形提升了

char,short类型参与运算都会整形提升

比int大的就不用整形提升

sizeof括号内确实不参与运算,但整形提升看的是如果运算过后的结果

算术转换

向空间更大的,精度更高的去转换

long double

double

float

unsigned long int

long int

unsigned int

int

操作符属性

影响表达式求值的因素

  1. 操作符的优先级
  1. 操作符的结合性
  1. 是否控制求值顺序。

+的结合顺序L->R从左到右结合

&&会控制求值顺序 如最左边表达式已经为0,后面的表达式就不会再计算了

||

?:条件操作符

,逗号表达式

均会控制求值顺序

是否任何一个表达式就能计算出一个结果呢?

a*b + c*d + e*f
//计算的时候,由于*比+的优先级高,只能保证的计算是比+早,但是
//优先级并不能决定第三个*比第一个+早执行

a*b

c*d

ab + cd

e*f

ab + cd + e*f

或者:

a*b

c*d

e*f

ab + cd

ab + cd + e*f

int main()
{
 int i = 10;
 i = i-- - --i * ( i = -3 ) * i++ + ++i;
 printf("i = %d\n", i);
 return 0; }
int fun()
{
     static int count = 1;
     return ++count; }
int main()
{
     int answer;
     answer = fun() - fun() * fun();
     printf( "%d\n", answer);//输出多少?
     return 0; }
int main()
{
 int i = 1;
 int ret = (++i) + (++i) + (++i);
 printf("%d\n", ret);
 printf("%d\n", i);
 return 0; 
}

以上均为垃圾代码,不同平台结果不一样

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值