• CSAPP(补充)-- C++中正负数的反码操作


    C++ 中的反码计算,要先转补码,结果也要转为相应的补码,这个操作也体现出C++对数字的专一性,它内部实现逻辑的完整性,因为对于计算机中的有符号的数字都是以补码方式存储,代码中列举了有符号的数字反码计算流程

    #include 
    #include 
    #include 
    using namespace std;
    
    int main(){
        ios::sync_with_stdio(false);
        int b = -5;
        int a = ~b; 
        // -5 --> 100...101
        // 
        // 找出-5的补码 (c++会把这个数转成补码计算) 
        // 111...011
        //按位取反
        // 000...100
        // 正数的补码是自己,故成立
    
        //b = 5
        //b = 000..101
        // 补码就是自己,直接按位取反
        //~b = 111..010 (这个可以看作内存中的结果)
        //是个负数 取出他的补码 (就是在计算机中存储的方式)
    
        // next 100..101 + 1 = 100..110 = -6 (因为我定义的是int, 所以相当于经历了向有符号的转变。
    
        //综上所述,为了求得反码,需要分别考虑正数和负数的开端和结果的情况
        // 都要转为补码进行运算
        // or 直接根据公式来算 
        // -a = ~a + 1
    
        cout << a << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    扩展
    对于计算机而言是不需要判断有符号数和无符号数的,都是一样地处理,大概学校里不少老师也都是这么教的,这个话确实是对的,但是得加个限制条件“在硬件层面”,在软件层面并不完全如此,至少在汇编层面还是会区分有符号数和无符号数的。汇编对于有符号数和无符号数的加法指令是通用的,但是乘法和除法指令是有两套的,这个区分是由编译器完成的,高级语言转汇编时会根据变量类型调用不同的汇编函数

    show you the code.

    在Intel的64位X86CPU上,Windows系统下使用Visual Studio用C语言进行测试。

    先看看加法,对于如下的C代码段1,得到转成的汇编代码如汇编代码段1。

    //C代码段1
    #include
    int main() {
        int a = 12;
        int b = 20;
        int c = a + b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    转成汇编://汇编代码段1

    #include
    int main() {
    00C21750  push        ebp  
    00C21751  mov         ebp,esp  
    00C21753  sub         esp,0E4h  
    00C21759  push        ebx  
    00C2175A  push        esi  
    00C2175B  push        edi  
    00C2175C  lea         edi,[ebp-0E4h]  
    00C21762  mov         ecx,39h  
    00C21767  mov         eax,0CCCCCCCCh  
    00C2176C  rep stos    dword ptr es:[edi]  
    00C2176E  mov         ecx,offset _DC84FF0F_test@c (0C2C003h)  
    00C21773  call        @__CheckForDebuggerJustMyCode@4 (0C21307h)  
    	int a = 12;
    00C21778  mov         dword ptr [a],0Ch  
    	int b = 20;
    00C2177F  mov         dword ptr [b],14h  
    	int c = a + b;
    00C21786  mov         eax,dword ptr [a]  
    00C21789  add         eax,dword ptr [b]  
    00C2178C  mov         dword ptr [c],eax  
    }
    00C2178F  xor         eax,eax  
    00C21791  pop         edi  
    00C21792  pop         esi  
    00C21793  pop         ebx  
    00C21794  add         esp,0E4h  
    00C2179A  cmp         ebp,esp  
    00C2179C  call        __RTC_CheckEsp (0C21230h)  
    00C217A1  mov         esp,ebp  
    00C217A3  pop         ebp  
    00C217A4  ret 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    对于如下的C代码段2,得到转成的汇编代码如汇编代码段2。//C代码段2

    #include
    int main() {
        unsigned int a = 12;
        unsigned int b = 20;
        unsigned int c = a + b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    转成汇编://汇编代码段2

    #include
    int main() {
    007B1750  push        ebp  
    007B1751  mov         ebp,esp  
    007B1753  sub         esp,0E4h  
    007B1759  push        ebx  
    007B175A  push        esi  
    007B175B  push        edi  
    007B175C  lea         edi,[ebp-0E4h]  
    007B1762  mov         ecx,39h  
    007B1767  mov         eax,0CCCCCCCCh  
    007B176C  rep stos    dword ptr es:[edi]  
    007B176E  mov         ecx,offset _DC84FF0F_test@c (07BC003h)  
    007B1773  call        @__CheckForDebuggerJustMyCode@4 (07B1307h)  
    	unsigned int a = 12;
    007B1778  mov         dword ptr [a],0Ch  
    	unsigned int b = 20;
    007B177F  mov         dword ptr [b],14h  
    	unsigned int c = a + b;
    007B1786  mov         eax,dword ptr [a]  
    007B1789  add         eax,dword ptr [b]  
    007B178C  mov         dword ptr [c],eax  
    }
    007B178F  xor         eax,eax  
    007B1791  pop         edi  
    007B1792  pop         esi  
    007B1793  pop         ebx  
    007B1794  add         esp,0E4h  
    007B179A  cmp         ebp,esp  
    007B179C  call        __RTC_CheckEsp (07B1230h)  
    007B17A1  mov         esp,ebp  
    007B17A3  pop         ebp  
    007B17A4  ret
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    可以看到对于都是正数的整型数相加和无符号整型数相加,他们转成汇编是完全一致的。这也很容易理解,对于整型数12、20和无符号整型数12、20,他们在内存中是完全一致的,相加指令也相同。那么我们考虑下正数和负数相加呢?整型数情况//C代码段3

    #include
    int main() {
        int a = -12;
        int b = 8;
        int c = a + b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    转成汇编://汇编代码段3

    #include
    int main() {
    008C1750  push        ebp  
    008C1751  mov         ebp,esp  
    008C1753  sub         esp,0E4h  
    008C1759  push        ebx  
    008C175A  push        esi  
    008C175B  push        edi  
    008C175C  lea         edi,[ebp-0E4h]  
    008C1762  mov         ecx,39h  
    008C1767  mov         eax,0CCCCCCCCh  
    008C176C  rep stos    dword ptr es:[edi]  
    008C176E  mov         ecx,offset _DC84FF0F_test@c (08CC003h)  
    008C1773  call        @__CheckForDebuggerJustMyCode@4 (08C1307h)  
    	int a = -12;
    008C1778  mov         dword ptr [a],0FFFFFFF4h  
    	int b = 8;
    008C177F  mov         dword ptr [b],8  
    	int c = a + b;
    008C1786  mov         eax,dword ptr [a]  
    008C1789  add         eax,dword ptr [b]  
    008C178C  mov         dword ptr [c],eax  
    }
    008C178F  xor         eax,eax  
    008C1791  pop         edi  
    008C1792  pop         esi  
    008C1793  pop         ebx  
    008C1794  add         esp,0E4h  
    008C179A  cmp         ebp,esp  
    008C179C  call        __RTC_CheckEsp (08C1230h)  
    008C17A1  mov         esp,ebp  
    008C17A3  pop         ebp  
    008C17A4  ret  无符号整型数情况//C代码段4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    #include
    int main() {
        unsigned int a = -12;
        unsigned int b = 8;
        unsigned int c = a + b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    转成汇编://汇编代码段4

    #include
    int main() {
    00D41750  push        ebp  
    00D41751  mov         ebp,esp  
    00D41753  sub         esp,0E4h  
    00D41759  push        ebx  
    00D4175A  push        esi  
    00D4175B  push        edi  
    00D4175C  lea         edi,[ebp-0E4h]  
    00D41762  mov         ecx,39h  
    00D41767  mov         eax,0CCCCCCCCh  
    00D4176C  rep stos    dword ptr es:[edi]  
    00D4176E  mov         ecx,offset _DC84FF0F_test@c (0D4C003h)  
    00D41773  call        @__CheckForDebuggerJustMyCode@4 (0D41307h)  
    	unsigned int a = -12;
    00D41778  mov         dword ptr [a],0FFFFFFF4h  
    	unsigned int b = 8;
    00D4177F  mov         dword ptr [b],8  
    	unsigned int c = a + b;
    00D41786  mov         eax,dword ptr [a]  
    00D41789  add         eax,dword ptr [b]  
    00D4178C  mov         dword ptr [c],eax  
    }
    00D4178F  xor         eax,eax  
    00D41791  pop         edi  
    00D41792  pop         esi  
    00D41793  pop         ebx  
    00D41794  add         esp,0E4h  
    00D4179A  cmp         ebp,esp  
    00D4179C  call        __RTC_CheckEsp (0D41230h)  
    00D417A1  mov         esp,ebp  
    00D417A3  pop         ebp  
    00D417A4  ret 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    可以看到这次结果还是完全一样,不管是整型数还是无符号整型数-12都是以补码形式存储在内存中,不过对于无符号整型数来说会把-12当成4294967284。
    原码:1000 0000 0000 0000 0000 0000 0000 1100
    反码:1111 1111 1111 1111 1111 1111 1111 0011
    补码:1111 1111 1111 1111 1111 1111 1111 0100(内存中存储的结果)

    8的原码和补码相同8的原码(补码):0000 0000 0000 0000 0000 0000 0000 1000
    相加后的结果是:
    补码相加:1111 1111 1111 1111 1111 1111 1111 1100(内存中存储的结果)
    反码 :1000 0000 0000 0000 0000 0000 0000 0011
    反码 :1000 0000 0000 0000 0000 0000 0000 0100这个最终内存中的结果如果视为整型数的补码,结果就是-4;
    视作无符号整型数就是4294967292,结果都是正确的,所以计算机对于整型数和无符号整型数的加法是完全一样地处理方法。

  • 相关阅读:
    eclipse进入断点之后,一直卡死,线程一直在运行【记录一种情况】
    关于jQuery实现轮播图和基本属性的操作
    基于C#的五子棋游戏设计
    Unity制作旋转光束
    【C++】GoogleTest入门指南
    移动应用测试快速指南
    超市商品管理系统 毕业设计 JAVA+Vue+SpringBoot+MySQL
    Docker下部署安装Mysql
    Xcode 异常图片导致ipa包增大问题
    近世代数——Part1 课后题目
  • 原文地址:https://blog.csdn.net/tian246319/article/details/127594457