负数的二进制表示

问题来源:

"为毛   -x=!x+1  ???

其中x为一任意int型正整数,左式表示取x的相反数后的二进制形式,右式表示先将x的二进制按位取反后再加一得到的二进制形式。

左右两个二进制相同"


假设有一个 int 类型的数,值为5,那么,我们知道它在计算机中表示为: 


00000000 00000000 00000000 00000101 


5转换成二制是101,不过int类型的数占用4字节(32位),所以前面填了一堆0。 


现在想知道,-5在计算机中如何表示? 


  


在计算机中,负数以原码的补码形式表达。 


什么叫补码呢?这得从原码,反码说起。 


  


原码:一个正数,按照绝对值大小转换成的二进制数;一个负数按照绝对值大小转换成的二进制数,然后最高位补1,称为原码。 


比如 00000000 00000000 00000000 00000101 是 5的 原码。 


          10000000 00000000 00000000 00000101 是 -5的 原码。 


  


反码:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。 


取反操作指:原为1,得0;原为0,得1。(1变0; 0变1) 


比如:正数00000000 00000000 00000000 00000101 的反码还是 00000000 00000000 00000000 00000101 


负数10000000 00000000 00000000 00000101每一位取反(除符号位),得11111111 11111111 11111111 11111010。 


称:11111111 11111111 11111111 11111010 是 10000000 00000000 00000000 00000101 的反码。 


反码是相互的,所以也可称: 


10000000 00000000 00000000 00000101 和 11111111 11111111 11111111 11111010互为反码。 


  


补码:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1. 


比如:10000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010。 


那么,补码为: 


11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011 




所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011。转换为十六进制:0xFFFFFFFB。 




再举一例,我们来看整数-1在计算机中如何表示。 


假设这也是一个int类型,那么: 




1、先取-1的原码:10000000 00000000 00000000 00000001 


2、得反码:     11111111 11111111 11111111 11111110(除符号位按位取反) 


3、得补码:     11111111 11111111 11111111 11111111 




可见,-1在计算机里用二进制表达就是全1。16进制为:0xFFFFFF 






主要知识点: 


正数的反码和补码都与原码相同。 
而负数的反码为对该数的原码除符号位外各位取反。 
负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1 


下面是书上原文: 


原码表示法规定:用符号位和数值表示带符号数,正数的符号位用“0”表示,负数的符号位用“1”表示,数值部分用二进制形式表示。 
反码表示法规定:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。 
补码表示法规定:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1.
正零和负零的补码相同,[+0]补=[-0]补=0000 0000B




<think>好的,用户现在想了解C语言中负数的位移操作以及负数二进制表示方法。我之前已经回答过关于取余运算的问题,其中提到了C语言的整数除法和余数符号的规则,可能用户现在对位运算和二进制表示感兴趣。 首先,我需要回忆C语言中负数二进制表示方式。根据引用[2]和[3],C语言使用补码来表示负数。补码的计算方式是原码取反后加1。例如,-10的补码是11110110(假设8位)。但需要注意,C语言中的整型提升和符号位扩展会影响位移操作的结果。 接下来是位移操作部分。用户特别提到负数的位移,这包括左移和右移。对于左移操作,C语言中的行为是将二进制位向左移动,低位补0。但负数左移可能会导致符号位改变,例如-10 << 1的结果是-20,这在二进制中相当于补码左移一位。但需要注意的是,左移有符号整数如果导致溢出,结果是未定义的,不过通常编译器会按位操作处理。 然后是右移操作。这里分为逻辑右移和算术右移。对于有符号负数,C语言标准规定右移是算术右移,即高位补符号位。例如,-10 >> 1的结果是-5,因为补码右移时高位补1,保持负数。而逻辑右移是高位补0,但C语言中只有无符号整数右移才会使用逻辑右移。 用户的问题可能涉及到具体的例子,比如引用[1]中的代码演示了负数左移的结果。需要解释为什么-10左移1位得到-20,以及二进制层面的变化。同时,结合引用[3]中的整型提升规则,位移操作前是否会发生整型提升?例如,char类型的负数在位移时会被提升为int,再进行位移操作,这可能影响结果。 另外,用户可能关心位移操作的应用场景和注意事项。比如,位移操作常用于位掩码、快速乘除运算等,但对于负数右移,需要注意符号位的填充,避免意外结果。同时,位移位数超过类型长度是未定义行为,需要避免。 最后,确保回答结构清晰,分点解释二进制表示和位移操作,并给出示例代码和注意事项。结合之前的引用内容,尤其是引用[2]和[3]中的补码和整型提升规则,来支持解释的准确性。同时,生成相关问题帮助用户进一步学习,比如补码的作用、算术位移与逻辑位移的区别等。</think>### C语言负数二进制表示与位移操作详解 --- #### **一、负数二进制表示** 在C语言中,**负数采用补码(Two's Complement)形式存储**[^2][^3]。补码规则如下: 1. **原码转补码**:绝对值二进制表示 → **按位取反 → 加1** 2. **补码特性**:最高位为符号位(1表示负数),简化了加减法运算 **示例:-10的补码表示(以8位为例)** 1. 原码:`1000 1010` 2. 反码:`1111 0101` 3. 补码:`1111 0110`(反码 + 1) 实际存储时,C语言会根据变量类型扩展位数(如32位int型): $$-10_{10} \rightarrow 11111111\ 11111111\ 11111111\ 11110110_2$$ --- #### **二、负数的位移操作规则** C语言中位移操作分为**左移(<<)**和**右移(>>)**,负数位移需特别注意符号位和整型提升规则[^3]。 --- ##### **1. 左移操作(<<)** - **规则**:二进制位整体左移,低位补0,高位溢出丢弃 - **符号位影响**:左移可能改变符号位(例如负数左移后变为正数) **示例:-10 << 1** ```c int num = -10; // 补码:1111 0110(简化后的8位表示) int n = num << 1; // 左移后补码:1110 1100 → 十进制值-20 ``` > 实际运算时,C语言会进行**整型提升**,将操作数扩展为int类型后再位移[^3] --- ##### **2. 右移操作(>>)** - **有符号数右移**:**算术右移**(高位补符号位) - **无符号数右移**:**逻辑右移**(高位补0) **示例:-10 >> 1** ```c int num = -10; // 补码:1111 0110 int n = num >> 1; // 算术右移后补码:1111 1011 → 十进制值-5 ``` --- #### **三、关键特性对比** | 操作类型 | 规则 | 负数示例(-10) | 结果 | |----------|-------------------------------|---------------------|-------| | 左移 | 低位补0,可能改变符号位 | `-10 << 1` | -20 | | 算术右移 | 高位补符号位,保持负数性质 | `-10 >> 1` | -5 | | 逻辑右移 | 高位补0(仅无符号数可用) | `(unsigned)-10 >> 1`| 大正数| --- #### **四、注意事项** 1. **位移位数限制** 若位移位数超过变量类型的位数(如int型位移32位),行为未定义(UB): ```c int a = -10; a << 33; // 未定义行为 ``` 2. **整型提升的影响** char/short类型在位移前会先提升为int类型[^3]: ```c char c = -10; // 补码:11110110 int n = c << 2; // 提升为int后再左移 ``` 3. **边界值处理** 左移负数可能导致溢出(如`INT_MIN << 1`),需谨慎处理。 --- #### **五、代码验证** ```c #include <stdio.h> void print_binary(int num) { for (int i = 31; i >= 0; i--) { printf("%d", (num >> i) & 1); if (i % 4 == 0) printf(" "); } printf("\n"); } int main() { int num = -10; printf("原始值: %d\n", num); printf("二进制: "); print_binary(num); // 输出补码形式 printf("\n左移1位: %d\n", num << 1); print_binary(num << 1); printf("\n右移1位: %d\n", num >> 1); print_binary(num >> 1); return 0; } ``` --- #### **相关问题** 1. 补码表示法如何简化计算机的加减法运算? 2. 在C语言中如何实现无符号数的逻辑右移? 3. 为什么算术右移能保持负数的符号特性? 4. 整型提升对位运算的实际影响有哪些?
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值