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
字节 Byte 8个位组成,基本存储单位
Word 通常16位(2字节)
双字 DWORD 32位(4字节)
四字 QWORD 64位(8字节)
MSB Most Significant Bit 最高有效位
LSB Least 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);