【C语言】操作符相关知识点

移位操作符

<< 左移操作符
>>右移操作符

  • 左移操作符 移位规则:
    左边抛弃、右边补0
    在这里插入图片描述

  • 右移操作符 移位规则:
    首先右移运算分两种:
    1.逻辑移位 左边用0填充,右边丢弃
    2.算术移位 左边用原该值的符号位填充,右边丢弃

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

警告⚠ : 对于移位运算符,不要移动负数位,这个是标准未定义的。例如:

int num = 10;
num>>-1;//error

sizeof 和数组

#include <stdio.h>
void test1(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;
}

问:
(1)、(2)两个地方分别输出多少?
(3)、(4)两个地方分别输出多少?

答:

  1. (1) 输出为:40
  2. (2) 输出为:8
  3. (3) 输出为:10
  4. (4) 输出为:8

这些输出结果的原因如下所述:

在 main 函数中,sizeof(arr) 表示整型数组 arr 的大小,即 10 个整型元素,每个整型占据 4 个字节(32 位系统下)。因此,sizeof(arr) 的结果为 10 * 4 = 40 字节。

在 main 函数中,sizeof(ch) 表示字符型数组 ch 的大小,即 10 个字符元素,每个字符占据 1 个字节。因此,sizeof(ch) 的结果为 10 字节。

在 test1 函数中,arr 参数虽然声明为整型数组,但在函数参数中数组会被转换为指针,因此 sizeof(arr) 实际上返回的是指针的大小,而不是整型数组的大小。在这里,指针的大小是 8 字节(64 位系统下)。

在 test2 函数中,同样地,ch 参数虽然声明为字符型数组,但在函数参数中数组也会被转换为指针,因此 sizeof(ch) 返回的是指针的大小,而不是字符型数组的大小。在这里,指针的大小是 8 字节(64 位系统下)。

区分逻辑与(或)和按位与(或)

1&2----->0
1&&2---->1
1|2----->3
1||2---->1

1&2 -----> 0
这里使用的是按位与(&)运算符,对应二进制的每一位进行与操作。1 的二进制表示为 01,2 的二进制表示为 10。按位与操作后,得到的结果是 00,即 0。

1&&2 ----> 1
这里使用的是逻辑与(&&)运算符,它是逻辑运算符,用于判断两个条件是否同时为真。在大多数编程语言中,逻辑与会进行短路求值,即如果第一个条件为假,则不会再计算第二个条件,直接返回假。因此,1&&2 中的 1 和 2 都被视为真,因此结果是 1。

1|2 -----> 3
这里使用的是按位或(|)运算符,对应二进制的每一位进行或操作。1 的二进制表示为 01,2 的二进制表示为 10。按位或操作后,得到的结果是 11,即 3。

1||2 ----> 1
这里使用的是逻辑或(||)运算符,用于判断两个条件是否有一个为真。逻辑或也会进行短路求值,即如果第一个条件为真,则不会再计算第二个条件,直接返回真。因此,1||2 中的 1 被视为真,因此结果是 1。

在很多编程语言中,比如 C、C++、Java 等,“&&” 是逻辑与运算符(logical AND operator)。当使用 “&&” 运算符时,它会对两个条件进行逻辑与操作,只有当两个条件都为真时,整个表达式的结果才为真(true),否则结果为假(false)。

在上述表达式"1&&2" 中,1 和 2 被视为条件,即非零值被视为真。因此,根据逻辑与运算符的规则,只有当两个条件都为真时,结果才为真。在这种情况下,1 和 2 都被视为真,所以整个表达式的结果为真,即 1。

一道笔试题

#include <stdio.h>
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;
}

现在我们来分析代码的执行过程:

初始时,a = 0, b = 2, c = 3, d = 4。
执行 i = a++ && ++b && d++:
首先计算 a++,a 先赋值给 i(i = 0),然后 a 自增为 1。此时 a 的值为 0,表示为假。
因为第一个条件已经为假,后续的条件不再执行,即 ++b 和 d++ 都不会被执行。
整个表达式因为第一个条件为假,所以结果为假,即 i 的值为 0。
因此,最终输出的结果是:

a = 1
b = 2
c = 3
d = 4

但是如果是注释掉的那一行,那么结果为,

a = 1b = 3c = 3
d = 4

逗号表达式

逗号表达式会依次计算每个表达式,并返回最后一个表达式的值作为整个表达式的值。

例如:

//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?

c为13

访问结构体

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

这段代码中,首先定义了一个结构体 Stu,包括姓名、年龄、性别和分数四个成员变量。然后定义了两个函数 set_age1 和 set_age2,分别用来设置学生的年龄。在 main 函数中,创建了一个 Stu 类型的对象 stu,并创建了一个指向该对象的指针 pStu。

接下来分析代码的执行过程:

  1. stu.age = 20; // 将 stu 的年龄设置为 20
  2. set_age1(stu); // 传递参数时会复制结构体,所以在 set_age1 函数中对参数进行的修改不会影响原始的 stu 对象。
  3. pStu->age = 20; // 通过指针 pStu 访问 age 成员,将年龄设置为 20
  4. set_age2(pStu); // 传递指针参数,可以直接修改原始的结构体对象。

因此,经过上述步骤后,stu 对象的年龄应该是 20,而 pStu 指向的对象的年龄应该是 18。所以最终输出的结果是:stu.age = 20,pStu->age = 18。

大小端

大小端(Endian)是指在存储多字节数据时,字节序的不同排列方式。主要有两种类型:大端序(Big-endian)和小端序(Little-endian)。

  1. 大端序(Big-endian):数据的高位字节存储在低地址,低位字节存储在高地址。即数据的最高有效字节存储在最低的地址,依次类推。

举例:十六进制数 0x12345678 在大端序中存储为:

地址     数据
0x00 -> 12
0x01 -> 34
0x02 -> 56
0x03 -> 78

小端序(Little-endian):数据的低位字节存储在低地址,高位字节存储在高地址。即数据的最低有效字节存储在最低的地址,依次类推。

举例:十六进制数 0x12345678 在小端序中存储为:

地址     数据
0x00 -> 78
0x01 -> 56
0x02 -> 34
0x03 -> 12

在计算机系统中,不同的处理器架构采用不同的字节序,而网络通信和数据交换等需要统一字节序以确保数据正确传输和解析。因此,在跨平台开发和数据通信时,需要注意数据的字节序问题。

为什么要存在大小端?

大小端的存在主要是由于不同的计算机体系结构和处理器架构在存储和处理多字节数据时的方式不同。以下是一些原因:

  1. 处理器架构差异:不同的处理器架构采用了不同的字节序。例如,x86 架构使用小端序,而某些 RISC 架构(如 ARM、PowerPC)使用大端序。这种差异导致在进行跨平台开发、数据交换和网络通信时需要考虑字节序的转换。

  2. 数据传输:在网络通信中,不同的系统之间需要传输数据。为了确保数据的正确传输和解析,发送方和接收方需要在数据传输过程中统一字节序。否则,接收方可能会错误地解释数据,导致数据损坏或解析错误。

  3. 数据存储:在文件和存储设备上存储数据时,字节序的一致性也很重要。如果不同系统上的程序读取和写入数据时使用不同的字节序,那么数据的解析将会出错。

因此,大小端的存在是为了解决不同系统间数据交换和解析的问题,确保数据的正确性和一致性。

判断大小端的程序:

#include<stdio.h>
#include<windows.h>
int main()
{union{int a;char c;}un;un.a = 1;if (un.c) {printf("小端\n");}else {printf("大端\n");}system("pause");return 0;
}

解释:
这段代码使用了 C 语言中的联合(union)来判断当前系统的字节序是大端序还是小端序。具体解释如下:

  • 定义了一个联合 un,其中包含一个整型变量 a 和一个字符变量 c。
  • 将整型变量 a 赋值为 1。
  • 利用联合的特性,修改 a 的同时也会影响到 c,因为它们共享同一块内存空间。
  • 判断 c 的值,如果 c 的值为非零,则说明当前系统采用小端序;如果 c 的值为 0,则说明当前系统采用大端序。
  • 最后通过打印输出来显示当前系统的字节序。

整型提升

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

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

通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。

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

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

用一个例子来体会一下:

#include<stdio.h>
//实例1
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 要进行整形提升,但是c不需要整形提升 a,b整形提升之后,变成了负数,所以表达式a==0xb6 , b==0xb600 的结果是假,但是c不发生整形提升,则表达式 c==0xb6000000 的结果是真。

另一个例子:

#include<stdio.h>
//实例2
int main()
{char c = 1;printf("%u\n", sizeof(c));printf("%u\n", sizeof(+c));printf("%u\n", sizeof(!c));return 0;
}

结果分析:

  1. sizeof ( c ):c 是一个字符型变量,占用一个字节。所以 sizeof© 的结果是 1。

  2. sizeof(+c):在 C 语言中,一元正号操作符会将操作数提升为整数类型。因此,+c 的结果将是一个 int 类型,占用 4 个字节。所以 sizeof(+c) 的结果应该是 4 而不是 1。

  3. sizeof(!c):逻辑非操作符 ! 会返回 0 或 1,而不改变数据类型的大小。所以 sizeof(!c) 的结果应该是 1。

  4. 表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,但是 sizeof© ,就是1个字节

截断

截断(truncation)是指将一个值的小数部分舍弃,只保留整数部分的操作。截断通常发生在从浮点数到整数的类型转换过程中。
如果将字节多的数据类型赋给一个占字节少的变量类型,会发生“截断”。

举例说明:

  1. 将浮点数截断为整数:
  • 假设有一个浮点数 x = 3.75,通过截断操作可以将其转换为整数 3。小数部分 .75 被舍弃,只保留了整数部分 3。
  • 可以使用不同的编程语言提供的截断函数或类型转换函数来进行这样的操作,例如在 Python 中使用 int() 函数,或在 C 语言中使用 (int) 强制类型转换。
  1. 截断位操作:
  • 在计算机领域,有时候我们需要对二进制数进行截断操作。例如,假设有一个 8 位的二进制数 10101101,如果我们只需要保留前 4 位,那么截断操作就可以将其变为 1010。
  • 在具体实现中,可以通过与运算(bitwise AND)来实现截断位操作。例如,在 C 语言中可以使用按位与操作符 &,如 result = number & 0xF0,其中 number 是原始的二进制数,0xF0 是一个掩码,表示前 4 位都为 1,其余位都为 0。这样的截断操作就可以保留目标位上的数值。

举个例子:

#include<stdio.h>
#include<windows.h>
int main()
{ char a = -1;signed char b = -1;unsigned char c = -1;printf("a=%d,b=%d,c=%d\n", a, b, c);system("pause");return 0;
}

以上代码的输出结果是:
a=-1, b=-1, c=255

这是因为在C语言中,char类型默认被定义为有符号类型(signed char),其取值范围为-128到127。当使用-1赋值给char类型变量a时,会将-1视为有符号数,因此a的值也为-1。

而对于signed char类型的变量b,虽然也是将-1赋值给它,但由于已经明确指定为有符号类型,所以它的值仍然是-1。

对于unsigned char类型的变量c,它是无符号类型,其取值范围为0到255。当将-1赋值给unsigned char类型变量c时,会发生截断操作。由于c是无符号类型,截断后的结果相当于对256取余,即-1+256=255。因此c的值为255。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/730144.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上门服务小程序|上门服务系统成品功能包含哪些?

随着移动互联网的快速发展&#xff0c;上门服务小程序成为了一种创新的家政服务模式。它不仅为用户带来了极大的便利&#xff0c;还能在提高服务效率和质量方面发挥作用。通过上门服务小程序&#xff0c;用户可以轻松预约按摩或理疗服务&#xff0c;无需繁琐操作&#xff0c;只…

knife4j生产环境禁止打开页面

Knife4j是一个集Swagger2 和 OpenAPI3为一体的增强解决方案&#xff0c;官网地址&#xff1a;Knife4j 集Swagger2及OpenAPI3为一体的增强解决方案. | Knife4j 考虑到安全性问题&#xff0c;在实际服务部署到生产环境后就需要禁用到swagger页面的展示&#xff0c;这个时候只需…

类和对象(1)(至尊详解版)

相信对于大家而言&#xff0c;对于类和对象都会是一头雾水吧&#xff01;什么是类&#xff1f;或者你有对象吗&#xff1f;那么本期的内容呢&#xff1f;就由我来为大家再次增加对于它们的理解&#xff0c;由于水平上的原因&#xff0c;可能会存在不当之处&#xff0c;敬请读者…

类与对象(三)--static成员、友元

文章目录 1.static成员1.1概念&#x1f3a7;面试题✒️1.2static的特性&#x1f3a7;1.3思考&#x1f3a7; 2.友元2.1什么是友元&#xff1f;&#x1f3a7;2.2两种友元关系&#xff1a;&#x1f3a7; 1.static成员 1.1概念&#x1f3a7; &#x1f50e; static关键字用于声明类…

Jmeter性能测试 -1

之前讲的Jmeter算不上是性能测试&#xff0c;只是用Jmeter做接口测试。现在我们开始进入实际的性能测试。开始前你应该对Jmeter有了一定的了解&#xff0c;把前面Jmeter内容看一遍应该可以入门了。 Jmeter与locust locust除了可以做接口的性能测试以外&#xff0c;做性能测试…

ubuntu18.04编译OpenCV-3.4.19+OpenCV_contrib-3.4.19

首先确保安装了cmake工具 安装opencv依赖文件 sudo apt-get install build-essential sudo apt-get install git libgtk-3-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev sudo apt-get install python3-dev python3-numpy libtbb2 libtbb-dev libjpeg-dev li…

树莓派(Raspberry Pi)常见的各种引脚介绍

本文将为您详细讲解树莓派&#xff08;Raspberry Pi&#xff09;常见的各种引脚&#xff0c;以及它们的特点、区别和优势。树莓派是一款非常受欢迎的单板计算机&#xff0c;它拥有多个 GPIO&#xff08;通用输入输出&#xff09;引脚&#xff0c;这些引脚可以用于各种电子项目和…

【C++】C++模板基础知识篇

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 泛型编程2. 函数模板2.1 函数模板概念2.2 函数模板格式2.3 函数模板的原理2.4 函数模板的实例化2.5 模板参数的匹配原则 3. 类模板3.1 类模板的定义格式3.2 类模板的实例化…

金智维售前总监屈文浩,将出席“ISIG-RPA超级自动化产业发展峰会”

3月16日&#xff0c;第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导&#xff0c;企智未来科技&#xff08;RPA中国、AIGC开放社区、LowCode低码时代&#xff09;主办。大会旨在聚合每一位产业成员的力量&#xff0c;深入探索R…

问题:前端获取long型数值精度丢失,后面几位都为0

文章目录 问题分析解决 问题 通过接口获取到的数据和 Postman 获取到的数据不一样&#xff0c;仔细看 data 的第17位之后 分析 该字段类型是long类型问题&#xff1a;前端接收到数据后&#xff0c;发现精度丢失&#xff0c;当返回的结果超过17位的时候&#xff0c;后面的全…

通知:T3学员领取资料391-395

各位T3学员∶本周VBA技术资料增加391-395讲&#xff0c;看到通知后联络我&#xff08;微&#xff1a;VBA6337&#xff09;免费领取资料。成果来之不易&#xff0c;您更新后请说声谢谢&#xff0c;感恩我的成果。 MF391&#xff1a;选择同颜色的单元格 MF392&#xff1a;连接范…

图文并茂的讲清楚Linux零拷贝技术

今天我们来聊一聊Linux零拷贝技术&#xff0c;今天我们以一个比较有代表性的技术sendfile系统调用为切入点&#xff0c;详细介绍一下零拷贝技术的原理。 1.零拷贝技术简介 Linux零拷贝技术是一种优化数据传输的技术&#xff0c;它可以减少数据在内核态和用户态之间的拷贝次数&…

图论入门题题解

✨欢迎来到脑子不好的小菜鸟的文章✨ &#x1f388;创作不易&#xff0c;麻烦点点赞哦&#x1f388; 所属专栏&#xff1a;刷题_脑子不好的小菜鸟的博客-CSDN博客 我的主页&#xff1a;脑子不好的小菜鸟 文章特点&#xff1a;关键点和步骤讲解放在 代码相应位置 拓扑排序 / 家谱…

寄存器(CPU工作原理)

文章目录 寄存器(CPU工作原理)1. 通用寄存器2. 字在寄存器中的存储3. 几条汇编指令4. 物理地址5. 16位结构的CPU6. 8086CPU给出物理地址的方法7. 段的概念8. 段寄存器9 . CS和IP10. 修改CS、IP的指令11. 代码段 寄存器(CPU工作原理) 一个典型的CPU由运算器、控制器、寄存器等器…

【好书推荐-第十期】《AI绘画教程:Midjourney使用方法与技巧从入门到精通》

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公众号&#xff1a;洲与AI。 &#x1f388; 本文专栏&#xff1a;本文收录…

005-事件捕获、冒泡事件委托

事件捕获、冒泡&事件委托 1、事件捕获与冒泡2、事件冒泡示例3、阻止事件冒泡4、阻止事件默认行为5、事件委托6、事件委托优点 1、事件捕获与冒泡 2、事件冒泡示例 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /…

VUE Element例子学习

参考:【前端】VueElement UI案例&#xff1a;通用后台管理系统-项目总结_vue elementui 管理系统-CSDN博客 之前参考的el-admin-web太复杂了&#xff0c;不是纯净的demo. 所以找了一圈资料&#xff0c;找到了这个博客&#xff0c;很合适&#xff0c;有例子的代码&#xff0c;…

【redis】模拟抢红包

1.使用的数据结构 思路是需要将指定数量的红包提前压栈&#xff0c;然后当用户来“抢红包”的时候&#xff0c;将红包取出来。 规定每个用户只能抢一次&#xff0c;并且最小金额是1块钱。 选择redis中的list结构模拟。 2.模拟发红包。 GetMapping("/give-red-packets&…

SpringCloudAlibaba微服务之Nacos架构及基础概念梳理

SpringCloudAlibaba微服务之Nacos架构及基础概念梳理 文章目录 SpringCloudAlibaba微服务之Nacos架构及基础概念梳理1. 官网介绍1. 简介2. Naocs是什么3. Nacos 地图4. Nacos 生态图 2. Nacos 架构1. 基本架构及概念1. 服务 (Service)2. 服务注册中心 (Service Registry)3. 服务…

投标中项目组织结构的设置以及调整(样式表,多级列表)

投标中项目组织结构的设置以及调整&#xff08;样式表&#xff0c;多级列表&#xff09;&#xff1a; 投标项目中需要处理大规模的文字排版&#xff0c;就是需要用到样式表&#xff08;解决层级关系&#xff09;&#xff0c;多级列表&#xff08;解决自动编号的问题&#xff0…