C&C++快速入门

4、进制与位

1、课程目标

  • 理解不同进制的概念和转换方法
  • 掌握二进制与十六进制在编程中的应用
  • 理解位(bit)和字节(byte)的关系
  • 能够进行进制间的手动转换

2、名词解释

术语英文说明
二进制Binary以2为基数的计数系统,只有0和1
八进制Octal以8为基数的计数系统,0-7
十进制Decimal以10为基数的日常计数系统,0-9
十六进制Hexadecimal以16为基数,0-9和A-F
Bit最小的数据单位,0或1
字节Byte8个位组成,基本存储单位
Word通常16位(2字节)
双字DWORD32位(4字节)
四字QWORD64位(8字节)
MSBMost Significant Bit最高有效位
LSBLeast Significant Bit最低有效位
大端序Big Endian高位字节存储在低地址
小端序Little Endian低位字节存储在低地址

3、使用工具

工具用途
Windows计算器(程序员模式)进制转换验证
HxD / 010 Editor十六进制编辑器
Python交互式环境快速验证转换

4、技术原理

1. 进制基础

十进制 123 = 1×10² + 2×10¹ + 3×10⁰

二进制 1011 = 1×2³ + 0×2² + 1×2¹ + 1×2⁰ = 8+0+2+1 = 11

十六进制 0x1A = 1×16¹ + 10×16⁰ = 16+10 = 26

2. 进制转换表

十进制  二进制    十六进制
0       0000      0x0
1       0001      0x1
2       0010      0x2
3       0011      0x3
4       0100      0x4
5       0101      0x5
6       0110      0x6
7       0111      0x7
8       1000      0x8
9       1001      0x9
10      1010      0xA
11      1011      0xB
12      1100      0xC
13      1101      0xD
14      1110      0xE
15      1111      0xF

3. 内存中的字节序

数值: 0x12345678

大端序 (网络字节序):
地址:   0x00  0x01  0x02  0x03
内容:   0x12  0x34  0x56  0x78

小端序 (x86/x64):
地址:   0x00  0x01  0x02  0x03
内容:   0x78  0x56  0x34  0x12

4、代码实现

1. C语言进制表示与输出

#include <stdio.h>

int main() {
    // 不同进制的表示方法
    int decimal = 255;           // 十进制
    int binary = 0b11111111;     // 二进制 (C99/GCC扩展)
    int octal = 0377;            // 八进制 (以0开头)
    int hex = 0xFF;              // 十六进制 (以0x开头)
    
    printf("=== 进制表示演示 ===\n");
    printf("十进制 255:\n");
    printf("  十进制输出: %d\n", decimal);
    printf("  八进制输出: %o\n", decimal);
    printf("  十六进制输出: %x (小写) / %X (大写)\n", decimal, decimal);
    
    // 验证各种表示是否相等
    printf("\n=== 验证相等性 ===\n");
    printf("decimal=%d, binary=%d, octal=%d, hex=%d\n", 
           decimal, binary, octal, hex);
    
    return 0;
}

2. 手动实现进制转换

#include <stdio.h>
#include <string.h>

// 十进制转二进制字符串
void DecToBin(int num, char* buffer, int size) {
    int i = 0;
    char temp[64] = {0};
    
    if (num == 0) {
        strcpy(buffer, "0");
        return;
    }
    
    while (num > 0 && i < 63) {
        temp[i++] = (num % 2) + '0';
        num /= 2;
    }
    
    // 反转字符串
    int len = i;
    for (int j = 0; j < len && j < size - 1; j++) {
        buffer[j] = temp[len - 1 - j];
    }
    buffer[len < size ? len : size - 1] = '\0';
}

// 二进制字符串转十进制
int BinToDec(const char* binStr) {
    int result = 0;
    int len = strlen(binStr);
    
    for (int i = 0; i < len; i++) {
        result = result * 2 + (binStr[i] - '0');
    }
    
    return result;
}

// 十六进制字符串转十进制
int HexToDec(const char* hexStr) {
    int result = 0;
    int len = strlen(hexStr);
    
    // 跳过0x前缀
    int start = 0;
    if (len > 2 && hexStr[0] == '0' && (hexStr[1] == 'x' || hexStr[1] == 'X')) {
        start = 2;
    }
    
    for (int i = start; i < len; i++) {
        int digit;
        if (hexStr[i] >= '0' && hexStr[i] <= '9') {
            digit = hexStr[i] - '0';
        } else if (hexStr[i] >= 'A' && hexStr[i] <= 'F') {
            digit = hexStr[i] - 'A' + 10;
        } else if (hexStr[i] >= 'a' && hexStr[i] <= 'f') {
            digit = hexStr[i] - 'a' + 10;
        } else {
            break;
        }
        result = result * 16 + digit;
    }
    
    return result;
}

int main() {
    char binBuffer[64];
    
    // 十进制转二进制
    DecToBin(255, binBuffer, sizeof(binBuffer));
    printf("255 的二进制: %s\n", binBuffer);
    
    // 二进制转十进制
    printf("11111111 的十进制: %d\n", BinToDec("11111111"));
    
    // 十六进制转十进制
    printf("0xDEADBEEF 的十进制: %u\n", HexToDec("0xDEADBEEF"));
    
    return 0;
}

3. 查看内存字节序

#include <stdio.h>

void PrintBytes(void* ptr, int size) {
    unsigned char* bytes = (unsigned char*)ptr;
    printf("内存地址: %p\n", ptr);
    for (int i = 0; i < size; i++) {
        printf("  偏移 %d: 0x%02X\n", i, bytes[i]);
    }
}

int main() {
    unsigned int value = 0x12345678;
    
    printf("=== 字节序检测 ===\n");
    printf("值: 0x%08X\n", value);
    PrintBytes(&value, sizeof(value));
    
    // 判断字节序
    unsigned char* firstByte = (unsigned char*)&value;
    if (*firstByte == 0x78) {
        printf("\n当前系统: 小端序 (Little Endian)\n");
    } else if (*firstByte == 0x12) {
        printf("\n当前系统: 大端序 (Big Endian)\n");
    }
    
    return 0;
}

4、课后作业

4.1、作业1:进制转换练习

将以下数值转换为其他进制(手算后用程序验证):

  • 十进制 1024 → 二进制、十六进制
  • 二进制 10101010 → 十进制、十六进制
  • 十六进制 0xCAFE → 十进制、二进制

4.2、作业2:实现完整转换工具

编写一个程序,能够:

  1. 接收用户输入的任意进制数值
  2. 自动检测输入进制(0x开头为十六进制,0b开头为二进制等)
  3. 输出该数值的十进制、二进制、八进制、十六进制表示

4.3、作业3:字节序转换函数

实现大端序和小端序的互相转换函数:

unsigned int SwapEndian32(unsigned int value);
unsigned short SwapEndian16(unsigned short value);