C++ 中的反码计算,要先转补码,结果也要转为相应的补码,这个操作也体现出C++对数字的专一性,它内部实现逻辑的完整性,因为对于计算机中的有符号的数字都是以补码方式存储,代码中列举了有符号的数字反码计算流程
#include
#include
#include
扩展
对于计算机而言是不需要判断有符号数和无符号数的,都是一样地处理,大概学校里不少老师也都是这么教的,这个话确实是对的,但是得加个限制条件“在硬件层面”,在软件层面并不完全如此,至少在汇编层面还是会区分有符号数和无符号数的。汇编对于有符号数和无符号数的加法指令是通用的,但是乘法和除法指令是有两套的,这个区分是由编译器完成的,高级语言转汇编时会根据变量类型调用不同的汇编函数
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
#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
对于如下的C代码段2,得到转成的汇编代码如汇编代码段2。//C代码段2
#include
int main() {unsigned int a = 12;unsigned int b = 20;unsigned int c = a + b;
}
转成汇编://汇编代码段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
可以看到对于都是正数的整型数相加和无符号整型数相加,他们转成汇编是完全一致的。这也很容易理解,对于整型数12、20和无符号整型数12、20,他们在内存中是完全一致的,相加指令也相同。那么我们考虑下正数和负数相加呢?整型数情况//C代码段3
#include
int main() {int a = -12;int b = 8;int c = a + b;
}
转成汇编://汇编代码段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
#include
int main() {unsigned int a = -12;unsigned int b = 8;unsigned int c = a + b;
}
转成汇编://汇编代码段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
可以看到这次结果还是完全一样,不管是整型数还是无符号整型数-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,结果都是正确的,所以计算机对于整型数和无符号整型数的加法是完全一样地处理方法。