您好,登录后才能下订单哦!
# C++原码、反码、补码实例分析
## 1. 数值在计算机中的表示基础
### 1.1 二进制与计算机存储
计算机中的所有数据最终都以二进制的形式存储和处理。对于整数类型,C++提供了多种有符号(signed)和无符号(unsigned)的表示方式。理解这些二进制表示形式对程序员至关重要,特别是在处理底层系统编程、位操作和性能优化时。
```cpp
#include <iostream>
#include <bitset>
void showBinary(int num) {
std::bitset<32> bits(num);
std::cout << num << " 的二进制表示: " << bits << std::endl;
}
int main() {
showBinary(10); // 正数示例
showBinary(-10); // 负数示例
return 0;
}
原码是最直观的二进制表示方法: - 最高位表示符号(0正1负) - 其余位表示数值的绝对值
例如(8位情况下): - +5:00000101 - -5:10000101
原码的缺点: 1. 存在+0(00000000)和-0(10000000)两种零表示 2. 加减运算复杂,需要判断符号位
反码是为了解决原码运算问题提出的改进方案: - 正数的反码与原码相同 - 负数的反码:符号位不变,数值位按位取反
计算示例(8位): - +7:00000111(原码)→ 00000111(反码) - -7:10000111(原码)→ 11111000(反码)
void showOnesComplement(int num) {
if (num >= 0) {
std::bitset<32> bits(num);
std::cout << num << " 的反码: " << bits << std::endl;
} else {
std::bitset<32> bits(~(-num));
std::cout << num << " 的反码: " << bits << std::endl;
}
}
虽然反码解决了部分运算问题,但仍存在: 1. 零的两种表示问题(00000000和11111111) 2. 加减运算时仍需考虑符号位 3. 边界情况处理复杂
现代计算机普遍采用补码表示有符号整数,因为它: 1. 统一了零的表示(只有00000000) 2. 加减运算无需特殊处理符号位 3. 可以表示比原码和反码多一个负数
补码的计算方法: - 正数:与原码相同 - 负数:反码 + 1
void showTwosComplement(int num) {
std::bitset<32> bits(num);
std::cout << num << " 的补码: " << bits << std::endl;
}
// 手动计算补码示例
void manualTwosComplement(int num) {
if (num >= 0) {
std::cout << "正数补码与原码相同\n";
} else {
unsigned int absVal = -num;
std::bitset<32> inverted = ~absVal;
std::bitset<32> complement = inverted.to_ulong() + 1;
std::cout << "手动计算 " << num << " 的补码: " << complement << std::endl;
}
}
补码的本质是利用模运算概念: - 对于n位二进制,模为2^n - 负数x的补码 = 2^n - |x|
例如8位情况下: - -5的补码 = 256 - 5 = 251 = 11111011
这使得加减法可以统一处理:
7 - 5 = 7 + (-5) = 00000111 + 11111011 = (1)00000010 → 2(忽略进位)
#include <climits>
void showTypeRanges() {
std::cout << "char范围: " << CHAR_MIN << " 到 " << CHAR_MAX << std::endl;
std::cout << "unsigned char范围: 0 到 " << UCHAR_MAX << std::endl;
std::cout << "short范围: " << SHRT_MIN << " 到 " << SHRT_MAX << std::endl;
std::cout << "int范围: " << INT_MIN << " 到 " << INT_MAX << std::endl;
}
void showMemoryRepresentation(int num) {
unsigned char* p = reinterpret_cast<unsigned char*>(&num);
std::cout << num << " 的内存表示(小端序): ";
for (size_t i = 0; i < sizeof(num); ++i) {
std::cout << std::hex << static_cast<int>(p[i]) << " ";
}
std::cout << std::dec << std::endl;
}
void bitOperationsDemo() {
int x = 10; // 00001010
int y = 6; // 00000110
std::cout << "x & y: " << (x & y) << std::endl; // 00000010 → 2
std::cout << "x | y: " << (x | y) << std::endl; // 00001110 → 14
std::cout << "x ^ y: " << (x ^ y) << std::endl; // 00001100 → 12
std::cout << "~x: " << (~x) << std::endl; // 11110101 → -11(补码)
// 移位运算
std::cout << "x << 1: " << (x << 1) << std::endl; // 00010100 → 20
std::cout << "x >> 1: " << (x >> 1) << std::endl; // 00000101 → 5
// 负数移位
int z = -10;
std::cout << "z >> 1: " << (z >> 1) << std::endl; // 算术右移,保持符号位
}
bool isOdd(int n) {
return n & 1;
}
void swap(int& a, int& b) {
a ^= b;
b ^= a;
a ^= b;
}
int abs(int num) {
int mask = num >> (sizeof(int) * CHAR_BIT - 1);
return (num + mask) ^ mask;
}
void checkIntMin() {
int min = INT_MIN;
std::cout << "INT_MIN: " << min << std::endl;
std::cout << "-INT_MIN: " << -min << std::endl; // 仍然是负数,因为补码不对称
// 正确计算绝对值
int abs_min = (min == INT_MIN) ? INT_MAX : abs(min);
std::cout << "安全的绝对值: " << abs_min << std::endl;
}
bool addWillOverflow(int a, int b) {
if (b > 0) {
return a > INT_MAX - b;
} else {
return a < INT_MIN - b;
}
}
bool multiplyWillOverflow(int a, int b) {
if (a == 0 || b == 0) return false;
if (a > 0) {
if (b > 0) {
return a > INT_MAX / b;
} else {
return b < INT_MIN / a;
}
} else {
if (b > 0) {
return a < INT_MIN / b;
} else {
return a < INT_MAX / b;
}
}
}
虽然本文主要讨论整数表示,但简要提一下浮点数:
void showFloatRepresentation(float f) {
unsigned char* p = reinterpret_cast<unsigned char*>(&f);
std::cout << f << " 的IEEE 754表示: ";
for (size_t i = 0; i < sizeof(f); ++i) {
std::cout << std::bitset<8>(p[i]) << " ";
}
std::cout << std::endl;
}
unsigned int u = 10;
int i = -5;
if (i < u) { // i会被隐式转换为无符号数,导致意外结果
std::cout << "这个比较可能不符合预期!" << std::endl;
}
int x = 1;
x << 31; // 有符号左移超过位数是未定义行为
char c = 128; // 可能实现定义的行为(通常是-128)
int multiplyByTwo(int x) { return x << 1; }
int divideByTwo(int x) { return x >> 1; }
// 取低4位
int low4Bits = x & 0xF;
struct PackedData {
unsigned int flag1 : 1;
unsigned int flag2 : 1;
unsigned int value : 6;
};
通过本文的详细分析,我们深入理解了: 1. 原码、反码和补码的表示方法及其演变 2. 补码在现代计算机中的核心地位和数学原理 3. C++中各种整型的实际表示方式 4. 位操作的实际应用和注意事项
扩展阅读建议: - 《深入理解计算机系统》(CSAPP)第二章 - IEEE 754浮点数标准 - C++标准中的整数表示规定 - 二进制编码的历史发展
理解这些底层表示原理,将帮助您编写更高效、更可靠的C++代码,特别是在系统编程、嵌入式开发和性能关键型应用中。
本文共计约4950字,全面介绍了C++中的原码、反码和补码表示,包含大量代码示例和实际应用分析。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。