操作符详解—c语言

article/2025/9/13 20:47:23

目录

1. 操作符分类:

2. 算术操作符

3. 移位操作符 

3.1 左移操作符

3.2 右移操作符

4. 位操作符 

5. 赋值操作符 

6. 单目操作符

6.1 单目操作符介绍 

7. 关系操作符

8. 逻辑操作符 

9. 条件操作符 

10. 逗号表达式 

11. 下标引用、函数调用和结构成员 

12. 表达式求值 

12.1 隐式类型转换 

12.2 算术转换 

12.3 操作符的属性 


1. 操作符分类:

  算术操作符移位操作符位操作符赋值操作符单目操作符关系操作符逻辑操作符条件操作符逗号表达式下标引用、函数调用和结构成员

2. 算术操作符

                                  +   -  *  /  %

1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数

3. 移位操作符 

<< 左移操作符  将二进制序列向左移动
>> 右移操作符  将二进制序列向右移动

说起移位操作符就要说到二进制了

整数的二进制位表示有三种形式:原码 补码 反码

正整数的原码反码补码都相同

而负整数的反码与补码是要计算的

符号位 0 - 表示正数

            1 - 表示负数

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

               int a = 5
原码 000000000000000000000000000000000101
反码 000000000000000000000000000000000101
补码 000000000000000000000000000000000101
                               int a = -5
原码 10000000000000000000000000000101
反码 11111111111111111111111111111010 (原码的符号位不变,其他位取反的就是补码)
补码 11111111111111111111111111111011  (反码+1就是补码)

3.1 左移操作符

左移:就是将二进制序列左边丢弃,右边补0

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

 程序运行结果

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

程序运行结果

注意:编译器打印出来的值都是原码 

负数的原码 反码 补码的转换规则

3.2 右移操作符

右移分两种

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

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

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

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

4. 位操作符 

& //按(二进制)位与  (对应的二进制位只要有0就为0,只有全1才为1)
//按(二进制)位或     (对应的二进制位只要有1就为1,只有全0才为0)
^ //按(二进制)位异或 (对应的二进制位相同的为0,相异的为1)
注:他们的操作数必须是整数

int main()
{int a = 3;int b = -5;int c = a & b;int d = a | b;int e = a ^ b;printf("%d\n", c);printf("%d\n", d);printf("%d\n", e);return 0;
}
00000000000000000000000000000011  -> 3的补码
11111111111111111111111111111011  -> -5的补码(再次提醒,编译器打印出来的是原码,而正数原码反码补码相同)
00000000000000000000000000000011  -> 3&-5的结果 结果是3(补码)
11111111111111111111111111111011  -> 3|-5的结果
10000000000000000000000000000101  (原码) 结果是-5(补码)
11111111111111111111111111111000  -> 3^-5的结果
10000000000000000000000000001000  (原码) 结果是-8

程序运行结果

一道变态的面试题:

不能创建临时变量(第三个变量),实现两个数的交换

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

初学者没指望会,知道有这么一种方法即可。

5. 赋值操作符 

赋值操作符是一个很棒的操作符,它可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。

int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值

复合赋值符 

+= -= *= /= %= >>= <<= &= |= ^=

比如:int x += 2 ;  //x = x+2

6. 单目操作符

6.1 单目操作符介绍 

!      逻辑反操作
-      负值
+      正值
&      取地址
sizeof    操作数的类型长度(以字节为单位)
~      对一个数的二进制按位取反
--      前置、后置--
++      前置、后置++
*      间接访问操作符(解引用操作符)
(类型)    强制类型转换 

C语言中0表示假,非0表示真

int num =10;
if(num)
{printf("hehe\n);
}//!num 就是假 if语句不进入

1.sizeof(数组名),数组名不是数组首元素的地址,数组名表示整个数组,计算的是整个数组的大小.除这种情况之外,所有的数组名都表示数组首元素的地址。 

 sizeof是一个操作符,不是函数,计算类型创建的变量所占内存的大小,单位是字节 。

sizeof()中的表达式不参与计算 

一道有关sizeof的恶心的题目

#include <stdio.h>
int i;
int main()
{i--;if (i > sizeof(i)){printf(">\n");}else{printf("<\n");}return 0; 
}

问:程序会输出什么内容?

解释:首先全局变量如果没被初始化,会被默认设置成0,所以此时i的值就是0;而sizeof操作符,它的返回值是size_t的,size_t代表的是无符号的数,这里这个表达式就要(i > sizeof(i))进行算术转换,编译器会自动将左侧i自动转换为无符号整形的数据,-1对应的无符号整形是一个非常大的数字,超过4或者8,故最后的结果是打印出来“>”。

& 取地址和 * 间接访问操作符(解引用操作符)

int main()
{//& 取地址操作符//* 解引用操作符(间接访问操作符)int a = 10;int* pa = &a;*pa = 20;//* - 解引用操作符////*&a ==> a;return 0;
}

7. 关系操作符

> >= < <= !=  ==

没什么好说的 

8. 逻辑操作符 

&&   逻辑与
||      逻辑或

逻辑与 只有左右两个表达式全为真,整个表达式才为真

逻辑或 只有左右两个表达式全为假,整个表达式才为假 

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;
}

分析:i = a++ || ++b || d++; a++先使用a,再++,ay一·开始是0,往下走,++b,先b++,在使用,而整个表达式的值已经为真,则后面的d++没有执行,故程序运行结果是1 ,3 ,3 ,4。

9. 条件操作符 

exp1 ? exp2 : exp3

如果语句1为真,表达式结果就为语句2,反之则为语句3 

int main()
{int a = 3;int b = 5;int m = (a > b ? a : b);printf("%d\n", m);return 0;
}

10. 逗号表达式 

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

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

11. 下标引用、函数调用和结构成员 

1. [ ] 下标引用操作符

操作数:一个数组名 + 一个索引值

int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
[ ]的两个操作数是arr和9

2. ( ) 函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。

注意:可以没有参数

3. 访问一个结构的成员
 .  结构体.成员名
-> 结构体指针 ->成员名 

#include <stdio.h>
struct Stu
{char name[10];int age;char sex[5];double score;};void set_age1(struct Stu stu)
{stu.age = 18;
}void set_age2(struct Stu* pStu)
{pStu->age = 18;//结构成员访问
}int main()
{struct Stu stu;struct Stu* pStu = &stu;//结构成员访问stu.age = 20;//结构成员访问set_age1(stu);pStu->age = 20;//结构成员访问set_age2(pStu);return 0;
}

12. 表达式求值 

表达式求值的顺序一部分是由操作符的优先级和结合性决定。
同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。 

12.1 隐式类型转换 

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


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

char a,b,c;
...
a = b + c;

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

加法运算完成之后,结果将被截断,然后再存储于a中。

如何进行整体提升呢?

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

//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0

举两个例子 

int main()
{char c1 = 3;//首先要进行整型提升//00000000000000000000000000000011//00000011 - c1char c2 = 127;//首先要进行整型提升//00000000000000000000000001111111//01111111 - c2char c3 = c1 + c2;//00000000000000000000000000000011//00000000000000000000000001111111//00000000000000000000000010000010// 这里要发生截断//10000010 - c3// 此时c1是字符型,但我们是要以整型形式打印,所以还要进行整型提升。//11111111111111111111111110000010 补码//11111111111111111111111110000001 反码 //10000000000000000000000001111110 原码//-126printf("%d\n", 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;
}

例子中的 a,b 要进行整形提升,但是c不需要整形提升a,b整形提升之后,变成了负数,所以表达式 a==0xb6 , b==0xb600 的结果是假,但是c不发生整形提升,则表达式 c==0xb6000000 的结果是真.
所程序输出的结果是: c

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

c只要参与表达式运算,就会发生整形提升,表达式 +c ,就会发生提升,所以 sizeof(+c) 是4个字节.
表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,但是 sizeof(c) ,就是1个字节. 

12.2 算术转换 

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

long double
double
float
unsigned long int
long int
unsigned int
int

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

12.3 操作符的属性 

复杂表达式的求值有三个影响的因素。
1. 操作符的优先级(一定是相邻操作符)
2. 操作符的结合性
3. 是否控制求值顺序。
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。

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

比如,该代码在几种编译环境下得出的结果都不相同。

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


http://chatgpt.dhexx.cn/article/sIIZs4iX.shtml

相关文章

【SV】流操作符

流操作符 作用 把其后的数据打包成一个比特流 >>和<< 操作符>>把数据从左向右变成流&#xff0c;<<则把数据从右到左变成流。 注意&#xff1a; 可以指定一个片段宽度&#xff0c;把源数据按照这个宽度分段以后再转变成流。 例如 h{>>1{j}} 或…

C语言操作符总结

目录 1.算术操作符 2.移位操作符 3.位操作符 4.赋值操作符 5.单目操作符 6.关系操作符 7.逻辑操作符 8.条件操作符 9.逗号表达式 10.下标引用、函数调用和结构成员 C语言中操作符总共有10种&#xff0c;分别是&#xff1a; 算术操作符&#xff0c;移位操作符&#xf…

C语言操作符汇总

目录 一、算术操作符 二、移位操作符 三、位操作符 四、赋值操作符 五、单目操作符 六、关系操作符 七、逻辑操作符 八、条件操作符 九、逗号表达式 十、下标引用、函数调用和结构成员 C语言的操作符分为以下10种&#xff1a; 算术操作符移位操作符位操作符赋值操作…

python 操作符

1.注释: 三种 # " " " 2.输入输出 输出:print() 输入input() 3.变量 保存数据的,就是一个容器 变量名 值 修改变量的值:变量名 新值 *变量的命名: a-z A-Z 0-9 _ 注意:不能以数字开头,就以字母开头就好,_有特殊的作用,不能使用关键字 关键字: …

VHDL的操作符

一、赋值操作符 作用在于更新被赋值数据对象的值&#xff0c;数据对象主要是指信号和变量。VHDL赋值操作符也有信号赋值与变量赋值的区别&#xff0c;分别是&#xff1a; ”<"是信号赋值操作符&#xff0c;可以对标量型的信号类型对象或是矢量型信号类型对象整体赋值…

操作符详解(C语言)

目录 算术操作符(运算符)&#xff1a; - * / % 1、/ &#xff08;除法&#xff09; 2、% (取模、取余&#xff09; 移位操作符&#xff1a; << (左移&#xff09; >>(右移&#xff09; 注意&#xff1a;移位操作符的操作数只能是整数 1、<< …

Java中的类变量和实例变量的区别

类变量也叫静态变量&#xff0c;也就是在变量前加了static 的变量&#xff1b; 实例变量也叫对象变量&#xff0c;即没加static 的变量&#xff1b; 区别在于&#xff1a; 类变量和实例变量的区别在于&#xff1a;类变量是所有对象共有&#xff0c;其中一个对象将它值改变&…

python面向对象类变量的调用和改变

python中对类变量的访问 在python中对类变量的访问有两种方式 方式一&#xff1a;使用类名.变量名 方法二&#xff1a;使用对象名. 变量名 注意&#xff1a;但在使用方法二时&#xff0c;需要注意&#xff0c;在当前对象中是否具有与类变量同名的实例变量&#xff0c;若没有&am…

如何理解Java的类变量、成员变量、常量、类属性、实例属性、字段(field)、成员方法、类方法

文章目录 变量相关概念变量/常量类变量/静态变量成员变量/实例变量类属性/实例属性/对象属性什么是 field 成员变量和类变量的区别两个变量的生命周期不同访问方式不同数据存储位置不同 方法相关概念示例代码判断题 变量相关概念 变量/常量 所谓变量就是指可以改变的数据量&a…

第7.12节 可共享的Python类变量

第7.12节 可共享的Python类变量 一、 引言 在上节已经引入介绍了类变量和实例变量&#xff0c;类体中定义的变量为类变量&#xff0c;默认属于类本身&#xff0c;实例变量是实例方法中定义的self对象的变量&#xff0c;对于每个实例都是独有数据&#xff0c;而类变量是该类…

Java基础---类变量和实例变量

类变量和实例变量 成员变量&#xff1a;把类内、方法体外的变量称为成员变量。 package com.chen.offer.BiliBili;/*** author chenshimiao* Email 16622880228163.com* date 2022/2/18 10:27 下午** 区分成员变量 实例变量和类变量*/ public class Clothes {//实例变量Strin…

什么是类变量,什么是实例变量,它们之间有什么区别?

了解术语很重要。实例变量和类变量都是成员变量。它们都是成员变量&#xff0c;因为它们都与特定类相关联。但是&#xff0c;实例变量和类变量之间存在差异。 实例变量 实例变量属于类的实例。换句话说&#xff0c;实例变量属于对象&#xff0c;因为对象是类的实例。每个对象都…

Java类变量的初始化

目录 两个必须的知识点 字节码指令验证 结果分析 非法前向引用变量 最近在学JVM&#xff0c;在学到类的初始化的时候明白了以前不是很理解的类中静态变量的初始化的过程&#xff0c;如果你也对静态变量的初始化有所困扰或者如下图的输出结果有所疑惑&#xff0c;相信你看完…

如何使用Arthas查看类变量值

使用arthas查看类变量值核心思路是&#xff1a;通过实现ApplicationContextAware接口定义ApplicationUtil类&#xff0c;该类可以获取ApplicationContext的所有的Bean实例&#xff0c;然后通过arthas的ognl查看类实例中的属性值。 搭建简易Spring Boot工程 1. pom依赖 <?…

类变量(静态变量),静态方法(类方法)快速了解一篇足矣

什么是类变量&#xff1f; 类变量也叫静态变量&#xff0c;静态属性&#xff0c;是该类所有对象共享的变量&#xff0c;任何一个该类的对象去访问他时&#xff0c;取到的值都是相同的值&#xff0c;同样任何一个该类对象 去修改他时&#xff0c;修改的也是同一个变量。 如何定…

VS 关于 .sln 文件和 .suo 文件

Visual Studio.NET采用两种文件类型&#xff08;.sln和.suo&#xff09;来存储特定于解决方案的设置,它们总称为解决方案文件。为解决方案资源管理器提供显示管理文件的图形接口所需的信息&#xff0c;从而在每次继续开发任务时&#xff0c;不会因开发环境而分散精力&#xff1…

Linux命令ln -snf给文件创建软链接和硬链接

我们知道 ln 命令用于创建链接文件,ln命令的参数选项有很多,此处主要理解 -snf三个: -s:--symbolic比较容易,有-s时表示创建软连接,没有-s时,表示创建硬链接 -f:--force 强行删除任何已存在的目标文件 -n:--no-dereference 把符号链接的文件视为一般文件 一、创建软链…

Visual studio中.sln、.ncb、.rc、.sdf、.def、.vcproj等后缀文件解释

.sln 解决方案文件 Visual Studio使用解决方案文件(后缀为sln的文件)表示一个项目组&#xff0c;它通常包含一个项目中所有的工程文件信息。 .ncb 无编译浏览文件 无编译浏览文件&#xff1a;其中存放了供ClassView、WizardBar和Component Gallery使用的信息&#xff0c;由VC开…

凸函数的性质、判定,凸规划

一. 凸函数的性质 二. 凸函数的判别 判断一个函数是否为凸函数&#xff0c;最基本的方法是使用其定义。 对可微函数&#xff1a; 三、凸规划定义 最优化问题的目标函数为凸函数&#xff0c;不等式约束函数也为凸函数&#xff0c;等式约束函数是仿射的&#xff0c;则称该最优化问…

不等式约束问题-KKT条件 (1)

允许不等式约束的KKT条件&#xff08;卡罗需-库恩-塔克条件&#xff0c;Karush-Kuhn-Tucker Conditions&#xff0c;有时称为一阶必要条件&#xff09;是对只允许等式约束的拉格朗日乘数法的推广。 定义一个优化问题如下&#xff0c;该最优问题既有等式约束&#xff0c;又有不…