MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

C 语言多进制间互转换

2023-08-205.3k 阅读

一、C 语言中的进制基础

1.1 常见进制概述

在计算机领域,我们经常会遇到不同进制的数字表示。常见的进制有十进制(Decimal)、二进制(Binary)、八进制(Octal)和十六进制(Hexadecimal)。

  • 十进制:我们日常生活中最常用的进制,使用 0 - 9 这十个数字来表示数值。例如,数字 123 就是十进制数,它表示 1×10² + 2×10¹ + 3×10⁰。
  • 二进制:计算机底层数据存储和处理所采用的进制,仅由 0 和 1 两个数字组成。在二进制中,每一位的权重是 2 的幂次方。例如,二进制数 101 表示 1×2² + 0×2¹ + 1×2⁰,换算成十进制就是 5。
  • 八进制:由 0 - 7 这八个数字组成。八进制在早期的计算机系统中常用于表示文件权限等信息。在八进制中,每一位的权重是 8 的幂次方。例如,八进制数 34 表示 3×8¹ + 4×8⁰,换算成十进制为 28。
  • 十六进制:使用 0 - 9 以及 A - F(或 a - f)来表示数值,其中 A - F 分别对应十进制的 10 - 15。十六进制常用于表示内存地址、颜色值等。在十六进制中,每一位的权重是 16 的幂次方。例如,十六进制数 0x2A(前缀 0x 表示这是一个十六进制数)表示 2×16¹ + 10×16⁰,换算成十进制是 42。

1.2 C 语言中不同进制的表示方式

在 C 语言中,不同进制的常量有不同的表示方法:

  • 十进制常量:直接书写数字即可,例如 10、25、100 等。
  • 二进制常量:在 C99 标准之后,可以使用前缀 0b 或 0B 来表示二进制常量。例如,0b101 表示二进制数 101,即十进制的 5。
  • 八进制常量:以数字 0 开头表示八进制常量。例如,034 表示八进制数 34,换算成十进制是 28。
  • 十六进制常量:以 0x 或 0X 开头表示十六进制常量。例如,0x2A 表示十六进制数 2A,即十进制的 42。

二、十进制与其他进制的转换

2.1 十进制转二进制

将十进制数转换为二进制数,常用的方法是除 2 取余法。具体步骤如下:

  1. 将十进制数除以 2,记录余数。
  2. 将商继续除以 2,再次记录余数,直到商为 0。
  3. 从下往上将记录的余数排列,即可得到对应的二进制数。

下面是一个 C 语言代码示例:

#include <stdio.h>

void decimalToBinary(int decimal) {
    int binary[32];
    int i = 0;
    while (decimal > 0) {
        binary[i] = decimal % 2;
        decimal = decimal / 2;
        i++;
    }
    for (int j = i - 1; j >= 0; j--) {
        printf("%d", binary[j]);
    }
}

int main() {
    int decimal = 13;
    printf("十进制数 %d 转换为二进制为: ", decimal);
    decimalToBinary(decimal);
    return 0;
}

2.2 十进制转八进制

十进制转八进制同样可以使用除 8 取余法,步骤与十进制转二进制类似:

  1. 将十进制数除以 8,记录余数。
  2. 将商继续除以 8,再次记录余数,直到商为 0。
  3. 从下往上将记录的余数排列,得到对应的八进制数。

以下是 C 语言代码示例:

#include <stdio.h>

void decimalToOctal(int decimal) {
    int octal[32];
    int i = 0;
    while (decimal > 0) {
        octal[i] = decimal % 8;
        decimal = decimal / 8;
        i++;
    }
    for (int j = i - 1; j >= 0; j--) {
        printf("%d", octal[j]);
    }
}

int main() {
    int decimal = 50;
    printf("十进制数 %d 转换为八进制为: ", decimal);
    decimalToOctal(decimal);
    return 0;
}

2.3 十进制转十六进制

十进制转十六进制使用除 16 取余法,不过在处理余数大于 9 时,需要将其转换为对应的十六进制字符(A - F)。步骤如下:

  1. 将十进制数除以 16,记录余数。
  2. 如果余数小于 10,直接记录;如果余数大于等于 10,将其转换为对应的十六进制字符(10 对应 A,11 对应 B,以此类推)。
  3. 将商继续除以 16,重复上述步骤,直到商为 0。
  4. 从下往上将记录的结果排列,得到对应的十六进制数。

以下是 C 语言代码示例:

#include <stdio.h>

void decimalToHexadecimal(int decimal) {
    char hexadecimal[32];
    int i = 0;
    while (decimal > 0) {
        int remainder = decimal % 16;
        if (remainder < 10) {
            hexadecimal[i] = remainder + '0';
        } else {
            hexadecimal[i] = remainder - 10 + 'A';
        }
        decimal = decimal / 16;
        i++;
    }
    for (int j = i - 1; j >= 0; j--) {
        printf("%c", hexadecimal[j]);
    }
}

int main() {
    int decimal = 255;
    printf("十进制数 %d 转换为十六进制为: ", decimal);
    decimalToHexadecimal(decimal);
    return 0;
}

2.4 二进制、八进制、十六进制转十进制

  • 二进制转十进制:将二进制数的每一位乘以 2 的相应幂次方,然后将结果相加。例如,对于二进制数 101,计算为 1×2² + 0×2¹ + 1×2⁰ = 5。
  • 八进制转十进制:将八进制数的每一位乘以 8 的相应幂次方,然后将结果相加。例如,八进制数 34 计算为 3×8¹ + 4×8⁰ = 28。
  • 十六进制转十进制:将十六进制数的每一位乘以 16 的相应幂次方,然后将结果相加。对于十六进制数 0x2A,计算为 2×16¹ + 10×16⁰ = 42。

以下是将二进制、八进制、十六进制转换为十进制的 C 语言代码示例:

#include <stdio.h>
#include <math.h>

int binaryToDecimal(char *binary) {
    int decimal = 0;
    int length = strlen(binary);
    for (int i = 0; i < length; i++) {
        decimal += (binary[i] - '0') * pow(2, length - 1 - i);
    }
    return decimal;
}

int octalToDecimal(char *octal) {
    int decimal = 0;
    int length = strlen(octal);
    for (int i = 0; i < length; i++) {
        decimal += (octal[i] - '0') * pow(8, length - 1 - i);
    }
    return decimal;
}

int hexadecimalToDecimal(char *hexadecimal) {
    int decimal = 0;
    int length = strlen(hexadecimal);
    for (int i = 0; i < length; i++) {
        if (hexadecimal[i] >= '0' && hexadecimal[i] <= '9') {
            decimal += (hexadecimal[i] - '0') * pow(16, length - 1 - i);
        } else if (hexadecimal[i] >= 'A' && hexadecimal[i] <= 'F') {
            decimal += (hexadecimal[i] - 'A' + 10) * pow(16, length - 1 - i);
        } else if (hexadecimal[i] >= 'a' && hexadecimal[i] <= 'f') {
            decimal += (hexadecimal[i] - 'a' + 10) * pow(16, length - 1 - i);
        }
    }
    return decimal;
}

int main() {
    char binary[] = "101";
    char octal[] = "34";
    char hexadecimal[] = "2A";

    printf("二进制数 %s 转换为十进制为: %d\n", binary, binaryToDecimal(binary));
    printf("八进制数 %s 转换为十进制为: %d\n", octal, octalToDecimal(octal));
    printf("十六进制数 %s 转换为十进制为: %d\n", hexadecimal, hexadecimalToDecimal(hexadecimal));

    return 0;
}

三、二进制与八进制、十六进制的转换

3.1 二进制转八进制

由于 8 是 2 的 3 次方,所以二进制转八进制可以按三位一组进行转换。从二进制数的低位开始,每三位一组,不足三位的在高位补 0。然后将每组二进制数转换为对应的八进制数。

例如,对于二进制数 10110,分组为 010 110,010 转换为八进制是 2,110 转换为八进制是 6,所以 10110 转换为八进制是 26。

以下是 C 语言代码示例:

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

void binaryToOctal(char *binary) {
    int length = strlen(binary);
    int remainder = length % 3;
    if (remainder!= 0) {
        char newBinary[32];
        int j = 0;
        for (int i = 0; i < 3 - remainder; i++) {
            newBinary[j++] = '0';
        }
        for (int i = 0; i < length; i++) {
            newBinary[j++] = binary[i];
        }
        newBinary[j] = '\0';
        strcpy(binary, newBinary);
    }
    length = strlen(binary);
    for (int i = 0; i < length; i += 3) {
        int group = (binary[i] - '0') * 4 + (binary[i + 1] - '0') * 2 + (binary[i + 2] - '0');
        printf("%d", group);
    }
}

int main() {
    char binary[] = "10110";
    printf("二进制数 %s 转换为八进制为: ", binary);
    binaryToOctal(binary);
    return 0;
}

3.2 二进制转十六进制

因为 16 是 2 的 4 次方,二进制转十六进制按四位一组进行转换。从二进制数的低位开始,每四位一组,不足四位的在高位补 0。然后将每组二进制数转换为对应的十六进制数。

例如,对于二进制数 1101110,分组为 0110 1110,0110 转换为十六进制是 6,1110 转换为十六进制是 E,所以 1101110 转换为十六进制是 6E。

以下是 C 语言代码示例:

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

void binaryToHexadecimal(char *binary) {
    int length = strlen(binary);
    int remainder = length % 4;
    if (remainder!= 0) {
        char newBinary[32];
        int j = 0;
        for (int i = 0; i < 4 - remainder; i++) {
            newBinary[j++] = '0';
        }
        for (int i = 0; i < length; i++) {
            newBinary[j++] = binary[i];
        }
        newBinary[j] = '\0';
        strcpy(binary, newBinary);
    }
    length = strlen(binary);
    for (int i = 0; i < length; i += 4) {
        int group = (binary[i] - '0') * 8 + (binary[i + 1] - '0') * 4 + (binary[i + 2] - '0') * 2 + (binary[i + 3] - '0');
        if (group < 10) {
            printf("%d", group);
        } else {
            printf("%c", group - 10 + 'A');
        }
    }
}

int main() {
    char binary[] = "1101110";
    printf("二进制数 %s 转换为十六进制为: ", binary);
    binaryToHexadecimal(binary);
    return 0;
}

3.3 八进制转二进制

八进制转二进制,只需将八进制的每一位转换为对应的三位二进制数即可。

例如,八进制数 34,3 转换为二进制是 011,4 转换为二进制是 100,所以 34 转换为二进制是 011100。

以下是 C 语言代码示例:

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

void octalToBinary(char *octal) {
    int length = strlen(octal);
    for (int i = 0; i < length; i++) {
        int digit = octal[i] - '0';
        for (int j = 2; j >= 0; j--) {
            printf("%d", (digit >> j) & 1);
        }
    }
}

int main() {
    char octal[] = "34";
    printf("八进制数 %s 转换为二进制为: ", octal);
    octalToBinary(octal);
    return 0;
}

3.4 十六进制转二进制

十六进制转二进制,将十六进制的每一位转换为对应的四位二进制数。对于十六进制字符 A - F(或 a - f),先转换为对应的十进制数 10 - 15,再转换为二进制。

例如,十六进制数 2A,2 转换为二进制是 0010,A(10)转换为二进制是 1010,所以 2A 转换为二进制是 00101010。

以下是 C 语言代码示例:

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

void hexadecimalToBinary(char *hexadecimal) {
    int length = strlen(hexadecimal);
    for (int i = 0; i < length; i++) {
        if (hexadecimal[i] >= '0' && hexadecimal[i] <= '9') {
            int digit = hexadecimal[i] - '0';
            for (int j = 3; j >= 0; j--) {
                printf("%d", (digit >> j) & 1);
            }
        } else if (hexadecimal[i] >= 'A' && hexadecimal[i] <= 'F') {
            int digit = hexadecimal[i] - 'A' + 10;
            for (int j = 3; j >= 0; j--) {
                printf("%d", (digit >> j) & 1);
            }
        } else if (hexadecimal[i] >= 'a' && hexadecimal[i] <= 'f') {
            int digit = hexadecimal[i] - 'a' + 10;
            for (int j = 3; j >= 0; j--) {
                printf("%d", (digit >> j) & 1);
            }
        }
    }
}

int main() {
    char hexadecimal[] = "2A";
    printf("十六进制数 %s 转换为二进制为: ", hexadecimal);
    hexadecimalToBinary(hexadecimal);
    return 0;
}

3.5 八进制与十六进制的间接转换

由于八进制和十六进制之间没有直接简单的对应关系,我们可以通过十进制作为桥梁进行转换。即先将八进制转换为十进制,再将十进制转换为十六进制;或者先将十六进制转换为十进制,再将十进制转换为八进制。

以下是通过十进制进行八进制与十六进制转换的 C 语言代码示例:

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

int octalToDecimal(char *octal) {
    int decimal = 0;
    int length = strlen(octal);
    for (int i = 0; i < length; i++) {
        decimal += (octal[i] - '0') * pow(8, length - 1 - i);
    }
    return decimal;
}

void decimalToHexadecimal(int decimal) {
    char hexadecimal[32];
    int i = 0;
    while (decimal > 0) {
        int remainder = decimal % 16;
        if (remainder < 10) {
            hexadecimal[i] = remainder + '0';
        } else {
            hexadecimal[i] = remainder - 10 + 'A';
        }
        decimal = decimal / 16;
        i++;
    }
    for (int j = i - 1; j >= 0; j--) {
        printf("%c", hexadecimal[j]);
    }
}

int hexadecimalToDecimal(char *hexadecimal) {
    int decimal = 0;
    int length = strlen(hexadecimal);
    for (int i = 0; i < length; i++) {
        if (hexadecimal[i] >= '0' && hexadecimal[i] <= '9') {
            decimal += (hexadecimal[i] - '0') * pow(16, length - 1 - i);
        } else if (hexadecimal[i] >= 'A' && hexadecimal[i] <= 'F') {
            decimal += (hexadecimal[i] - 'A' + 10) * pow(16, length - 1 - i);
        } else if (hexadecimal[i] >= 'a' && hexadecimal[i] <= 'f') {
            decimal += (hexadecimal[i] - 'a' + 10) * pow(16, length - 1 - i);
        }
    }
    return decimal;
}

void decimalToOctal(int decimal) {
    int octal[32];
    int i = 0;
    while (decimal > 0) {
        octal[i] = decimal % 8;
        decimal = decimal / 8;
        i++;
    }
    for (int j = i - 1; j >= 0; j--) {
        printf("%d", octal[j]);
    }
}

int main() {
    char octal[] = "34";
    char hexadecimal[] = "2A";

    printf("八进制数 %s 转换为十六进制为: ", octal);
    int decimal = octalToDecimal(octal);
    decimalToHexadecimal(decimal);
    printf("\n");

    printf("十六进制数 %s 转换为八进制为: ", hexadecimal);
    decimal = hexadecimalToDecimal(hexadecimal);
    decimalToOctal(decimal);
    printf("\n");

    return 0;
}

四、实际应用场景

4.1 计算机底层数据处理

在计算机底层,如操作系统内核、驱动程序开发等场景中,经常需要对二进制数据进行处理。了解不同进制间的转换对于理解内存中的数据存储、位操作等非常重要。例如,在处理硬件寄存器的值时,常常需要将二进制数据转换为更易读的十六进制来进行调试和分析。

4.2 网络编程

在网络编程中,IP 地址的表示和处理涉及到进制转换。IP 地址通常以点分十进制的形式表示(如 192.168.1.1),但在网络传输中实际是以二进制形式存在。程序员需要能够在不同表示形式之间进行转换,以实现正确的网络通信和地址解析。

4.3 图形图像处理

在图形图像处理领域,颜色值常以十六进制表示。例如,RGB 颜色模式中,每种颜色分量(红、绿、蓝)可以用一个十六进制数表示。了解进制转换有助于在程序中对颜色值进行操作和处理,如颜色混合、亮度调整等。

通过对 C 语言中多进制间互转换的深入学习和实践,我们能够更好地理解计算机数据的表示和处理方式,为编写高效、灵活的程序奠定坚实的基础。无论是在底层系统开发还是应用层编程中,进制转换的知识都具有重要的实用价值。在实际编程过程中,我们应根据具体需求选择合适的算法和数据结构来实现进制转换,以提高程序的性能和可读性。同时,不断练习和优化代码,能够使我们在面对各种复杂的进制转换任务时更加得心应手。