当给16位的unsigned short 对象赋值100000,赋的值是什么?

本文探讨了当给16位无符号short类型变量赋值超过其最大值65535时,如何理解赋值过程。通过十六进制表示,解释了编译器会截取数值的低16位,而丢弃高位,从而导致实际赋值为34464,并提供了两种不同的解释来理解这个过程。

 习题2.4,P11.

// ------

16位unsigned short : 最大是65535  ( 即2^16-1)

unsigned short z;

int x = 100 000 用十六进制表示是 : 0X186A0, 它的低十六位是  86A0 ,对应十进制的34464

z赋值100 000 就会越界,编译器  截取 100 000 的二进制的低16位86A0赋予x,把高位0X10000 扔掉 

 

两种解释:

(1)相当于是 用100 000 对65536取模,即余下部分 : 100 000 - 65536  =  34464

(2) 好比是只有16个空格, 把100 000 的二进制往空格填,从右边的低位开始,依次向左填入,填满了16格,多余的就扔掉.

      因为扔掉的是高位(按十进制看,数比低位的大),扔掉的是 0X10000 = 65536,也就是把超过65535的部分扔掉.

        (因为0XFFFF = 65535,  所以: 0XFFFF + 1 = 0X10000 ---- > 0X10000 = 65535+1 = 65536 )

 

#include <iostream>
using namespace std;


void main()
{
	int x = 100000;
	cout.setf(ios::hex,ios::basefield);//设置十六进制显示数值  
	cout.setf(ios::showbase|ios::uppercase);//设置0x头和大写

    cout<<"十六进制x = "<<x<<endl;


     unsigned short z;  // 该类型最大是65535
	 z = x;				//  100000 > 65535  越界
	 cout<<"十六进制z = : "<<z<<endl;

	 cout.setf(ios::dec,ios::basefield); //改回来,用十进制显示
	 cout<<"十进制z = "<<z<<endl;
	 
}


 

<think> 我们有一个无符号短整型变量 `cameraStatus`,需要对其第1到第4(即最低为第0,或者我们可以理解为从右往左数,第0、第1、第2、第3)进行赋值。 注意:通常,置有两种计数方式: - 方式1:最低为第0,然后依次为第1、第2...(这是最常见的方式) - 方式2:最低为第1,但这种方式不常见。 根据问题描述,我们按照最常见的方式(最低是第0)来理解,那么第1到第4实际上是指从低到高的第1、第2、第3、第4(共4个)。注意,这里第1实际上是二进制表示中从右向左数的第二(因为第0是最低)。 但是,问题中说的是“1-4”,如果我们从1开始计数(即第1是最低),那么我们需要明确。为了避免混淆,我们按照标准方式(最低为第0)来重新解释问题: 如果用户希望的是最低为第1,那么: 第1:最低(原第0) 第2:次低(原第1) 第3:原第2 第4:原第3 但通常,在编程中,我们使用最低为第0。所以,我猜测用户的意思是:从最低开始数,第1到第4(共4),即实际上在标准序中(最低为0)的1到4(即第1、2、3、4,不包括第0)。 因此,我们假设用户想要设置的是标准序中的第1(即从右数第二)到第4(从右数第五,共4个)。 步骤: 1. 首先,我们需要将原来的cameraStatus的1-4清零。 2. 然后,将给定的4(假设为value)左移到相应的置。 3. 最后,将移后的与清零后的cameraStatus进行或操作。 注意:置是从0开始编号,所以第1到第4实际上是1、2、3、4(共4)。 具体操作: 假设我们有一个4(0到15之间),我们想将它放到cameraStatus的1到4上。 步骤: a. 清除cameraStatus的1到4:使用掩码,该掩码在1-4为0,其他为1。 掩码 = 0xFFE1 (因为1-4是第1到第4,即二进制中从右往左数第1(索引1)到第4(索引4)) 但是,我们也可以这样计算掩码: ~(0xF << 1) (因为我们要4,所以0xF,然后左移1,因为从第1开始) 具体: 掩码 = ~(0xF << 1); // 0xF是4个1,左移1变成第1到4为1,然后取反,则第1到4为0,其他为1。 b. 将需要设置的(假设为`value`,取范围0~15)左移1,对齐到第1到第4。 shifted_value = (value & 0xF) << 1; // 用0xF确保value只有低4有效,然后左移1 c. 将cameraStatus与掩码相与,清除原来的1-4,然后与shifted_value相或。 但是注意:如果直接使用掩码 `~(0xF<<1)`,在16系统中,0xF<<1是0x001E,取反后是0xFFE1,这是正确的。但是,如果unsigned short16,那么没问题。如果unsigned short是32,那么掩码就会有问题(因为0xF<<1只有低5,取反后高16都是1,这也没问题,因为我们要清除的只是低8中的1-4?)实际上,我们需要确保掩码的宽度与unsigned short的宽度相同。 更好的做法是使用类型宽度无关的方法: 掩码 = ~((unsigned short)0xF << 1); 这样,我们先将0xF转换为unsigned short,然后左移1,再取反,就可以得到正确宽度的掩码。 代码示例: unsigned short cameraStatus; unsigned short value; // 要设置的4(0~15) // 清除cameraStatus的第1-4(标准序的1到4) cameraStatus &= ~((unsigned short)0xF << 1); // 将value设置到第1-4 cameraStatus |= (value & 0xF) << 1; 注意:这里我们使用 `value & 0xF` 是为了确保value只有低4有效,避免传入的超过4。 另一种方法:我们也可以使用更通用的方法,即定义一个掩码常量,但使用上述方法可以适应不同的unsigned short宽度(16或更多,但通常16就够)。 如果用户所说的1-4是包括最低(即第0)?那么问题描述为“1-4”通常不包括第0,因为如果包括第0,那就应该是0-3(因为从0开始)。 所以,我们按照上述方法(清除第1-4,然后设置)是合理的。 但是,如果用户的意思是:将1-4(即第1、第2、第3、第4)设置为特定的4,那么上述代码就是正确的。 总结步骤: 1. 确定要设置的范围:从第1开始(最低为第0),共4(即第1、2、3、4)。 2. 创建掩码:将4个连续的1(0xF)左移1,得到0...0011110(二进制),然后取反,得到掩码(要清除的为0,其他为1)。 3. 用掩码与cameraStatus进行按与,清除这4。 4. 将给定的4(0-15)左移1,然后与cameraStatus进行按或。 注意:如果这个变量是16的,那么直接使用上述方法即可。如果实际数更多,但unsigned short通常是16,所以没有问题。 示例代码: unsigned short cameraStatus = 0x1234; // 假设原始 unsigned short value = 0x9; // 要设置的,二进制1001 // 清除第1到4 cameraStatus &= ~((unsigned short)0xF << 1); // 等价于 cameraStatus &= 0xFFE1; // 设置新 cameraStatus |= (value & 0xF) << 1; 这样,原来的第1到4被清除,然后被设置成了0x9<<1,即0x12(二进制10010),但注意这是移后的(因为左移了1,所以实际上是在第1到4放上了1001,即第1为0(1001的最低0放在第1),第2为1,第3为0,第4为1)。 验证: 原始:0x1234,二进制:0001 0010 0011 0100 我们要修改的是第1到4(即从右往左数,第1(索引1)到第4(索引4)),也就是上面二进制中从右往左数第1(0)到第4(0011的最后一个1是第3,然后0是第4?)实际上,我们按照4一组重新排列(16): 0001 0010 0011 0100 置(从右到左,从0开始): 0:0, 1:0, 2:1, 3:0, // 最低4:0100 -> 0=0, 1=0, 2=1, 3=0? 不对,实际上: 正确的置(从右往左,从0开始): 0:最右边(最低)0 1:次低0 2:1 3:0 4:1 5:1 6:0 7:0 8:0 9:1 10:0 11:0 12:1 13:0 14:0 15:0 所以,第1(索引1)到第4(索引4)就是上面1到4:1(0)、2(1)、3(0)、4(1)这四。 我们要将这四设置成新的,比如0x9(二进制1001),那么设置后: 1:1(1001的最低,因为左移1,所以1001变成10010,最低0在置0,而1在置1,0在置2,0在置3,1在置4?) 不对,移操作:将0x9(1001)左移1得到10010(二进制),即0x12。 然后与清除后的cameraStatus进行或操作。 清除操作:将原始cameraStatus的1到4清零(用掩码0xFFE1,即1111 1111 1110 0001),那么原始0x1234与0xFFE1相与: 0x1234: 0001 0010 0011 0100 0xFFE1: 1111 1111 1110 0001 相与: 0001 0010 0010 0001 -> 0x1221 然后或上0x12(即0000 0000 0001 0010): 0x1221: 0001 0010 0010 0001 0x0012: 0000 0000 0001 0010 或: 0001 0010 0011 0011 -> 0x1233 所以,最终cameraStatus变成了0x1233。 验证我们设置的1到4:在0x1233的二进制(0001 0010 0011 0011)中,0(最右边)是1,1是1,2是0,3是0,4是1?不对,实际上: 0011 0011 (最低80: 1, 1: 1, 2: 0, 3: 0, 4: 1, 5:1, ... 而我们设置的是1001(二进制),即我们希望1到4是:1=1, 2=0, 3=0, 4=1? 但是,我们移后是10010,所以: 0:0 1:1 2:0 3:0 4:1 所以,在结果中,0是1(原始0x1234的0是0,但是我们在清除操作中,0没有被清除(掩码在0是1),所以保留原始0?不对,原始0x1234的0是0,清除后还是0,然后或上0x12(0是0),所以0还是0。但是上面计算结果是0x1233,最低8是00110011,那么0是1?这不对。 重新计算: 原始:0x1234,二进制:0001 0010 0011 0100 掩码:0xFFE1,二进制:1111 1111 1110 0001 相与:0001 0010 0010 0000 (因为0011 0100 & 1110 0001 = 0010 0000,即0x1220) 然后或上0x12(0000 0000 0001 0010): 0001 0010 0010 0000 OR 0000 0000 0001 0010 = 0001 0010 0011 0010 -> 0x1232 所以,最终结果是0x1232。 现在,我们来看1到4(即从右往左,1、2、3、4): 最低8:0011 0010 0: 0 1: 1 2: 0 3: 0 4: 1 5: 1 6: 0 7: 0 所以,1到4是:1=1, 2=0, 3=0, 4=1 -> 二进制1001,即0x9,正确。 所以,代码正确。 另外,如果用户希望设置的1-4是包括第0,那么应该是0-3,那么方法类似,只需要调整移即可。 但是根据问题描述,用户明确说了是“1-4”,所以我们按照不包括0来处理。 因此,最终代码: cameraStatus &= ~((unsigned short)0xF << 1); // 清除1-4 cameraStatus |= (newValue & 0xF) << 1; // 设置新的 注意:newValue必须在0~15的范围内,我们通过`& 0xF`保证了这一点。 如果用户的环境可能对移操作有符号数的警告,可以全部用无符号操作。 另外,如果用户希望更通用的方法(比如任意置设置连续的),可以定义一个宏或者函数,但这里只需要固定置。 所以,针对用户的问题,这就是答案。 </think> ### 如何对 `unsigned short` 变量的特定赋值 #### 一、核心概念:操作原理 1. **置定义** - 假设最低为**第0**(最右侧),向高递增: ``` 置:15 14 ... 4 3 2 1 0 // 高← →低 编号:15 14 ... 4 3 2 1 0 // 标准编号 ``` - 需操作的 **1-4** 对应: - 第1 = 索引1(右起第2) - 第4 = 索引4(右起第5) 2. **操作逻辑**: ```mermaid graph LR A[原始] --> B[清除1-4] B --> C[新对齐] C --> D[按或合并] ``` #### 二、分步操作代码 ```c // 1. 定义变量 unsigned short cameraStatus = 0; // 初始 // 2. 创建清除掩码(1-4为0,其他为1) // 0xF = 0b1111,左移1覆盖1-4 unsigned short clearMask = ~(0xF << 1); // 得到0xFFE1(16系统) // 3. 清除目标域 cameraStatus &= clearMask; // 4. 准备新(确保4范围内) unsigned short newValue = 0x7; // 示例 0b0111 newValue &= 0xF; // 强制限制在4内 // 5. 移对齐到1-4 newValue <<= 1; // 左移1对齐 // 6. 写入新 cameraStatus |= newValue; ``` #### 三、操作过程详解 1. **清除旧**: ```c // 原始: 0bxxxx_xxxx_xxxx_xxxx // 清除掩码:0b1111_1111_1110_0001 = 0xFFE1 cameraStatus &= 0xFFE1; // 结果: 0bxxxx_xxxx_xxx0_000x ``` 2. **新对齐**: ```c newValue = 0x7; // 0b0111 newValue <<= 1; // 0b1110 → 对齐到1-4 ``` 3. **合并写入**: ```c // 清除后: 0bxxxx_xxxx_xxx0_000x // 新: 0b0000_0000_0000_1110 cameraStatus |= newValue; // 结果: 0bxxxx_xxxx_xxx0_111x ``` #### 四、验证示例 ```c #include <stdio.h> int main() { unsigned short cameraStatus = 0xFFFF; // 初始全1 unsigned short newValue = 0xB; // 0b1011 // 清除1-4 cameraStatus &= ~(0xF << 1); // 等价于 &= 0xFFE1 // 设置新 cameraStatus |= (newValue & 0xF) << 1; // 验证:输出二进制 printf("结果:0x%04X\n", cameraStatus); // 预期:0xFF61 (1111 1111 0110 0001) return 0; } ``` #### 五、关键注意事项 1. **域边界**: - 若操作其他域(如5-8): ```c // 修改左移量 unsigned short mask = ~(0xF << 5); cameraStatus |= (newValue & 0xF) << 5; ``` 2. **跨平台兼容**: ```c // 使用精确宽度类型 #include <stdint.h> uint16_t cameraStatus; ``` 3. **范围保护**: ```c // 确保输入不超过4 if(newValue > 0xF) { // 错误处理 } ``` #### 六、应用场景 1. **设备状态寄存器配置** 2. **协议头标志设置** 3. **硬件驱动开发** (如摄像头状态码、传感器控制字) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值