【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 = 1
 b = 3
 c = 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.mfbz.cn/a/440521.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ES分布式搜索-IK分词器

ES分词器-IK 1、为什么使用分词器&#xff1f; es在创建倒排索引时需要对文档分词&#xff1b;在搜索时&#xff0c;需要对用户输入内容分词。但默认的分词规则对中文处理并不友好。 我们在kibana的DevTools中测试&#xff1a; GET /_analyze {"analyzer": "…

最简k8s部署(AWS Load Balancer Controller使用)

问题 我需要在k8s集群里面部署springboot服务&#xff0c;通过k8s ingress访问集群内部的springboot服务&#xff0c;应该怎么做&#xff1f; 这里假设已经准备好k8s集群&#xff0c;而且也准备好springboot服务的运行镜像了。这里我们将精力放在k8s服务编排上面。 一图胜千言…

Supplementary Influence Maximization Problem in Social Networks

本论文发表于 IEEE TRANSACTIONS ON COMPUTATIONAL SOCIAL SYSTEMS, VOL. 11, NO. 1, FEBRUARY 2024 Abstract 由于在病毒式营销中的重要应用&#xff0c;影响力最大化&#xff08;IM&#xff09;已成为一个经过充分研究的问题。它的目的是找到一小部分初始用户&#xff0c;以…

智能问数,让数据对话变得如此简单

——用自然语言点亮数据智慧&#xff0c;让深度分析触手可及&#xff0c;让每个人都拥有私人数据分析师。 想象一下&#xff0c;曾经的数据查询&#xff0c;意味着面对着密密麻麻的电子表格&#xff0c;手动筛选、匹配与解读&#xff0c;耗费大量的时间与精力&#xff0c;或者…

【今日面经】24/3/8 又是Java后端面经啊啊啊啊啊啊啊

目录 1.osi七层模型&#xff1f;数据链路层是干什么的&#xff1f;2.tcp三次握手过程&#xff0c;tcp报文头部的结构&#xff1f;里面都有什么&#xff1f;3.讲讲超时重传和快重传&#xff0c;怎么等待的超时重传&#xff08;Timeout Retransmission&#xff09;快速重传&#…

高清数学公式视频素材、科学公式和方程式视频素材下载

适用于科普、解说的自媒体视频剪辑素材&#xff0c;黑色背景数学、科学公式和方程式视频素材下载。 视频编码&#xff1a;H.264 | 分辨率&#xff1a;3840x2160 (4K) | 无需插件 | 文件大小&#xff1a;16.12MB 来自PR视频素材&#xff0c;下载地址&#xff1a;https://prmuban…

Redis持久化机制之RDB内存快照

1、引言 我们经常在数据库层上加一层缓存&#xff08;如Redis&#xff09;&#xff0c;来保证数据的访问效率。 这样性能确实也有了大幅度的提升&#xff0c;因为从内存中取数远比从磁盘中快的多&#xff0c;但是本身Redis也是一层服务&#xff0c;也存在宕机、故障的可能性。…

蓝色经典免费wordpress模板主题

蓝色经典配色的免费wordpress建站主题&#xff0c;万能的wordpress建站主题。 https://www.wpniu.com/themes/24.html

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

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

O2OA(翱途)开发平台如何在流程表单中使用基于Vue的ElementUI组件?

本文主要介绍如何在O2OA中进行审批流程表单或者工作流表单设计&#xff0c;O2OA主要采用拖拽可视化开发的方式完成流程表单的设计和配置&#xff0c;不需要过多的代码编写&#xff0c;业务人员可以直接进行修改操作。 在流程表单设计界面&#xff0c;可以在左边的工具栏找到Ele…

Take-home questions——L3

Match the spatial domain image to the Fourier magnitude image 1—D 2—B 3—A 4—E 5—C

STM32F4串口波特率相关时钟

在main中调用的 Stm32_Clock_Init(336, 8, 2, 7); /* 设置时钟,168Mhz *///8*336/8/2168 时钟源,PLL寄存器配置函数: HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct) 系统时钟,总线寄存器配置,及HCLK时钟计算函数: HAL_StatusTyp…

用于回归的概率模型

机器学习中的回归方法&#xff1a; 机器学习中的概率模型 机器学习&#xff5c;总结了11种非线性回归模型&#xff08;理论代码可视化&#xff09; 高斯过程回归&#xff1a; Gaussian Processes for Machine Learning GPML——Datasets and Code Gaussian Processes 学…

力扣-数组题

1. 两数之和 找出map中是否有target-nums[i]&#xff0c; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {unordered_map<int, int> hash;for(int i 0 ;i < nums.size(); i){if(hash.find(target - nums[i]) ! hash…

Jmeter事务控制器实战

在性能测试工作中&#xff0c;我们往往只测试业务功能相关主要接口的数据请求和返回。然而实际上用户在使用web应用时&#xff0c;可能会加载诸多资源&#xff1a;htmldom、cssdom、javaScript、ajax请求、图片等。 从打开一个页面到界面渲染完成需要一定的加载时间&#xff0…

每日一题——1636.按照频率将数组升序排序

方法一 个人方法 用数组的键值对形式保存每个数字和他出现的次数&#xff0c;将对象的键值对转为数组&#xff0c;对数组进行自定义sort()排序&#xff0c;优先使用出现频次排序&#xff0c;如果出现频次一样就用大小就行排序。 排序完后按照出现频次拼接成字符串再转为数组 …

cannot change locale (zh_CN.UTF-8)

问题描述 在连接Centos7时出现告警提示 bash: warning: setlocale: LC_ALL: cannot change locale (zh_CN.UTF-8) /bin/sh: warning: setlocale: LC_ALL: cannot change locale (zh_CN.UTF-8) 原因分析 系统字符集配置问题 解决方案 查看可用的语言包&#xff0c;确保存在 …

网络基础aaa

三次握手 四次挥手 网络模型 TCP or UDP 的特点 如何理解 TCP 的5层协议 TCP的5层协议是指计算机网络体系结构中&#xff0c;与TCP&#xff08;传输控制协议&#xff09;相关的五个层次。这五个层次从高到低依次是&#xff1a;应用层、传输层、网络层、数据链路层和物理层。每…

cocos creator 3.7.2使用shader实现图片扫光特效

简介 功能&#xff1a;图片实现扫光效果 引擎&#xff1a;cocos Creator 3.7.2 开发语言&#xff1a;ts 完整版链接 链接https://lengmo714.top/284d90f4.html 效果图 shader代码 // Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd. CCEffect %{techniques:- pas…

特性螺旋面的刀具设计记录

最近和成型类刀具杠上了&#xff0c;这不最近有小伙伴提供了两个比较特殊的螺旋面工件&#xff0c;通常称作阴、阳转子。具体形状如下&#xff1a; 阴转子 阴转子端面齿形没看出有什么特殊的&#xff0c;但是在轴剖面齿形是内凹的&#xff0c;这个是比较特殊的形式。 阳转子…
最新文章