探索C/C++ 进制转换之美:从原理到应用

2023-05-16

一、简介 (Introduction)

进制前缀表示整数常量示例转换库接口参数及返回值示例
二进制0b 或 0B0b1010std::bitset<>std::bitset<8> binary(42); std::bitset<8> binary(“101010”);
八进制0075std::octstd::cout << std::oct << 42; int oct_num = std::stoi(“52”, nullptr, 8);
十进制无前缀42std::decstd::cout << std::dec << 42; int dec_num = std::stoi(“42”, nullptr, 10);
十六进制0x 或 0X0x2Astd::hexstd::cout << std::hex << 42; int hex_num = std::stoi(“2A”, nullptr, 16);

1.1 C/C++ 进制转换的基本概念 (Basic Concepts of Base Conversion in C/C++)

在计算机科学中,进制转换是一种非常重要的概念。它涉及将一个数值从一个进制系统(比如二进制、八进制、十进制或十六进制)转换到另一个进制系统。在C/C++编程语言中,我们通常会遇到需要对数值进行进制转换的情况,以满足不同的计算需求或实现特定功能。C/C++ 提供了多种进制转换方法,使得程序员能够方便地在不同进制系统之间进行转换。

在C/C++编程语言中,整数常量可以根据其前缀以不同的进制进行表示:

  • 无前缀整数常量表示十进制数(例如:42)
  • 0b0B为前缀的整数常量表示二进制数(例如:0b1010)
  • 0为前缀的整数常量表示八进制数(例如:075)
  • 0x0X为前缀的整数常量表示十六进制数(例如:0x2A)

此外,在C++中,还可以使用std::bitset类、std::stoi函数和std::stoi函数等库功能实现进制转换。

在以下章节中,我们将依次介绍C/C++进行进制转换的底层原理、基本方法和高级应用。希望能够帮助读者更深入地理解C/C++进制转换的原理和技巧,为实际编程工作提供参考。

1.2 进制转换的重要性及应用场景 (Importance and Application Scenarios of Base Conversion)

进制转换在计算机科学和C/C++编程中具有重要的地位,因为它广泛应用于各种实际场景,包括数据存储、通信、加密和解密等。具体的应用场景如下:

  1. 数据存储和压缩: 为了压缩数据和节省存储空间,开发人员需要使用不同的进制表示法(例如二进制或八进制)存储、传输和处理数据。进制转换可帮助开发人员在各种进制之间进行数据转换,以满足不同场景的需求。
  2. 通信协议: 很多通信协议要求以特定进制格式(如十六进制)表示数据。在这些情况下,进制转换变得至关重要,因为它可以帮助开发人员将数据转换为协议规定的格式,从而实现正确的数据传输。
  3. 硬件接口: 当与硬件设备(如传感器、通信设备等)进行编程时,开发人员经常需要处理二进制数据。因此,了解如何在C/C++中完成进制转换对于实现有效的硬件交互至关重要。
  4. 密码学: 在密码学领域,数据加密和解密需要进行多种复杂数学运算和逻辑操作。这些过程中经常涉及到不同的进制系统,如二进制、八进制和十六进制等。掌握C/C++中的进制转换技术可以帮助密码学家在加密算法实现中处理各种进制数据。
  5. 调试与分析: 在进行调试或分析程序时,我们可能需要查看内存中的原始数据。这些数据通常以十六进制表示,因此掌握进制转换技巧可以帮助我们更好地解释这些数据,从而找出潜在问题并优化代码。

这些都是为什么熟练掌握C/C++进制转换技巧极为重要的原因。在后续章节中,我们将详细介绍底层原理、基本方法以及高级应用,助您深入了解和掌握C/C++进制转换的相关知识。

1.3 本文结构与内容安排 (Structure and Content Arrangement of the Article)

为了帮助读者全面了解C/C++进制转换的相关知识,本文将从以下几个方面进行深入介绍:

  1. C/C++ 进制转换的底层原理:本部分将对计算机中的各种进制(二进制、八进制、十进制和十六进制)进行简要介绍,解析C/C++进行进制转换的基本原理以及类型转换与进制转换之间的关系。
  2. C/C++ 基本进制转换方法:在这一部分,我们将介绍C/C++进行八进制、十进制、十六进制之间的转换,以及二进制与其他进制之间的转换的基本方法。此外,还将探讨有关符号数进制转换的相关技巧。
  3. C/C++ 高级进制转换应用:本部分将向读者介绍在C/C++中不同进制表示法的读写,如何使用位操作符进行进制转换以及使用C++标准库中的进制转换功能。
  4. 总结与展望:在文章的最后一部分,将对前面所介绍的方法进行总结,并对未来发展与展望进行简要阐述。

通过对以上内容的深入讨论,我们希望能够帮助读者全面掌握C/C++的进制转换知识,为实际应用提供有力支持。在阅读本文的过程中,建议读者动手实践每个章节的示例代码,以更好地理解和掌握C/C++进制转换的技巧。

二、C/C++ 进制转换的底层原理 (Low-level Principles of Base Conversion in C/C++)

2.1 二进制、八进制、十进制与十六进制 (Binary, Octal, Decimal and Hexadecimal)

在计算机科学中,进制指的是数字系统的基数,也就是计算一个数值所用的基本单位数量。下面简要介绍四种常用的进制系统:

  1. 二进制 (Binary):二进制系统使用0和1两个数字表示数值。每一位只有两种可能的取值(0 或 1),向左移动一位相当于乘以 2。计算机底层使用二进制来存储和处理信息,因为它易于用电子电路实现。
  2. 八进制 (Octal):八进制系统使用数字0至7表示数值。每一位有8种可能的取值(0, 1, …, 7),向左移动一位相当于乘以 8。八进制在计算机科学中的应用主要是为了方便地表示二进制数,因为每三位二进制数可以转换为一位八进制数。
  3. 十进制 (Decimal):十进制系统使用数字0至9表示数值。每一位有10种可能的取值(0, 1, …, 9),向左移动一位相当于乘以 10。我们在日常生活中广泛使用十进制数,在不涉及底层计算机实现细节的编程任务中,通常会用十进制进行数值表示和运算。
  4. 十六进制 (Hexadecimal):十六进制系统使用数字0至9和字母A至F表示数值(其中A至F分别代表10-15)。每一位有16种可能的取值(0, 1, …, 9, A, B, C, D, E, F),向左移动一位相当于乘以 16。与八进制类似,使用十六进制主要是为了简化二进制数表示,每四位二进制数可以转换为一位十六进制数。

了解这些进制系统对于理解C/C++中的进制转换至关重要,接下来我们将讨论C/C++进制转换的基本原理。

2.2 C/C++ 进制转换的基本原理 (Basic Principles of Base Conversion in C/C++)

在C/C++编程中,使用进制转换技巧主要是为了在不同进制之间表示和处理数据。以下简要介绍C/C++进制转换的基本原理:

  1. 整数存储原理:计算机内部使用二进制系统存储整数。实际上,无论整数以二进制、八进制、十进制,还是十六进制表示,计算机内存中的存储形式都是相同的。当我们在C/C++中进行进制转换时,实际上是在操作这些二进制表示的数据。
  2. 数字进制与字符串表示的关系:在C/C++中,进制转换通常涉及将整数值在不同进制的字符串形式之间进行转换。例如,将整数42的十进制形式(“42”)转换为二进制形式(“101010”)。实际上,这种转换并不改变数值本身,而只是改变了它的表示形式。
  3. 进制转换算法:在C/C++中实现进制转换的关键是理解并掌握相应的转换算法。对于不同进制之间的转换,可以使用除法、取余运算和加法等基本数学运算实现。例如,将二进制数转换为十进制数时,可以通过将每一位乘以对应位权(2的指数幂)再求和实现。

通过理解C/C++进制转换的基本原理,我们可以更好地掌握在编程中如何在不同进制之间表示和处理数据。接下来,我们将探讨类型转换与进制转换之间的关系。

2.3 类型转换与进制转换 (Type Conversion and Base Conversion)

类型转换和进制转换是C/C++编程中两个密切相关的概念,它们在实际编程应用中起到了关键作用。下面简要介绍它们之间的关系:

  1. 类型转换:类型转换是指在C/C++编程中将一个数据类型的值转换为另一个数据类型的值。例如,将一个int类型的值转换为float类型的值。类型转换可以分为隐式类型转换和显式类型转换。隐式类型转换是编译器自动进行的转换,例如将一个较小的整数类型值赋给一个较大的整数类型变量。显式类型转换是程序员通过类型转换运算符(如static_cast)手动进行的转换。
  2. 与进制转换的关系:类型转换与进制转换在实践中经常一起使用。在进制转换过程中,我们通常需要首先将一个数值在不同数据类型之间进行转换,然后再将其转换为另一种进制。例如,在将一个二进制字符串转换为整数时,我们会先将字符串类型的二进制表示转换为整数值,然后再将二进制数转换为十进制数。在C/C++中,这类转换操作通常使用标准库函数实现,如std::stoistd::stol等。
  3. 注意事项:使用类型转换和进制转换时需要注意以下几点:
    • 遵循类型转换规则和进制转换算法,避免出现意外的结果。
    • 在进行进制转换时,务必考虑数值的范围,以防止溢出。
    • 在编写代码时,优先使用显式类型转换以明确表达转换意图,提高代码可读性。
    • 在实际应用中,根据需求选择合适的数据类型以及进制表示法,以提高运行效率和内存使用效率。

通过深入理解类型转换与进制转换之间的关系,我们可以更好地掌握C/C++编程中涉及进制转换的问题,并为实际应用提供有效解决方案。

三、C/C++ 基本进制转换方法 (Basic Base Conversion Methods in C/C++)

3.1 八进制、十进制、十六进制之间的转换 (Conversion between Octal, Decimal and Hexadecimal)

3.1.1 八进制与十六进制互转 (Octal and Hexadecimal Conversion)

在C/C++编程中,要将八进制数与十六进制数进行互相转换,通常需要经过以下几个步骤:

  1. 先将八进制数转换为十进制数。
  2. 再将十进制数转换为十六进制数。

以下是具体的转换示例:

  • 八进制转十六进制
#include <iostream>
#include <cstdio>
#include <sstream>

int main() {
    std::string octal_str = "75";
    int decimal_num;

    // 将八进制字符串转换为十进制整数
    std::istringstream(octal_str) >> std::oct >> decimal_num;

    // 将十进制整数转换为十六进制字符串
    std::stringstream hex_ss;
    hex_ss << std::hex << decimal_num;
    std::string hexadecimal_str = hex_ss.str();
    std::cout << "Hexadecimal: " << hexadecimal_str << std::endl;

    return 0;
}
  • 十六进制转八进制
#include <iostream>
#include <cstdio>
#include <sstream>

int main() {
    std::string hex_str = "2A";
    int decimal_num;

    // 将十六进制字符串转换为十进制整数
    std::istringstream(hex_str) >> std::hex >> decimal_num;

    // 将十进制整数转换为八进制字符串
    std::stringstream octal_ss;
    octal_ss << std::oct << decimal_num;
    std::string octal_str = octal_ss.str();
    std::cout << "Octal: " << octal_str << std::endl;

    return 0;
}

通过上述示例,我们可以学会在C/C++中实现八进制与十六进制的互相转换。接下来,我们将介绍如何在八进制与十进制之间进行转换。

3.1.2 八进制与十进制互转 (Octal and Decimal Conversion)

在C/C++编程中,要实现八进制与十进制之间的转换,我们可以使用标准库函数和流操作进行转换。

以下是具体的转换示例:

  • 八进制转十进制:
#include <iostream>
#include <sstream>

int main() {
    std::string octal_str = "75";
    int decimal_num;

    // 将八进制字符串转换为十进制整数
    std::istringstream(octal_str) >> std::oct >> decimal_num;

    std::cout << "Decimal: " << decimal_num << std::endl;

    return 0;
}
  • 十进制转八进制:
#include <iostream>
#include <sstream>

int main() {
    int decimal_num = 61;
    std::stringstream octal_ss;

    // 将十进制整数转换为八进制字符串
    octal_ss << std::oct << decimal_num;
    std::string octal_str = octal_ss.str();

    std::cout << "Octal: " << octal_str << std::endl;

    return 0;
}

通过上述示例,我们可以学会如何在C/C++中实现八进制与十进制之间的转换。下一节,我们将介绍如何在十进制与十六进制之间进行转换。

3.2 二进制与其他进制之间的转换 (Conversion between Binary and Other Bases)

3.2.1 二进制与八进制互转 (Binary and Octal Conversion)

在C/C++编程中,要实现二进制与八进制之间的转换,我们可以使用一些标准库函数和流操作进行转换。

以下是具体的转换示例:

  • 二进制转八进制:
#include <iostream>
#include <bitset>
#include <sstream>

int main() {
    std::string binary_str = "101010";
    std::bitset<32> binary_bitset(binary_str);
    std::stringstream octal_ss;

    // 将二进制字符串转换为对应的十进制整数
    unsigned long decimal_num = binary_bitset.to_ulong();

    // 将十进制整数转换为八进制字符串
    octal_ss << std::oct << decimal_num;
    std::string octal_str = octal_ss.str();
    std::cout << "Octal: " << octal_str << std::endl;

    return 0;
}
  • 八进制转二进制:
#include <iostream>
#include <bitset>
#include <sstream>

int main() {
    std::string octal_str = "52";
    int decimal_num;

    // 将八进制字符串转换为十进制整数
    std::istringstream(octal_str) >> std::oct >> decimal_num;

    // 将十进制整数转换为二进制字符串
    std::bitset<32> binary_bitset(decimal_num);
    std::string binary_str = binary_bitset.to_string();

    // 去除字符串前导零
    size_t non_zero_pos = binary_str.find_first_not_of('0');
    binary_str = binary_str.substr(non_zero_pos);

    std::cout << "Binary: " << binary_str << std::endl;

    return 0;
}

通过上述示例,我们可以学会如何在C/C++中实现二进制与八进制之间的转换。接下来,我们将介绍如何在二进制与十进制之间进行转换。

3.2.2 二进制与十进制互转 (Binary and Decimal Conversion)

在C/C++编程中,要实现二进制与十进制之间的转换,我们可以使用一些标准库函数和流操作进行转换。

以下是具体的转换示例:

  • 二进制转十进制:
#include <iostream>
#include <bitset>

int main() {
    std::string binary_str = "101010";
    std::bitset<32> binary_bitset(binary_str);

    // 将二进制字符串转换为对应的十进制整数
    unsigned long decimal_num = binary_bitset.to_ulong();
    std::cout << "Decimal: " << decimal_num << std::endl;

    return 0;
}
  • 十进制转二进制:
#include <iostream>
#include <bitset>

int main() {
    int decimal_num = 42;

    // 将十进制整数转换为二进制字符串
    std::bitset<32> binary_bitset(decimal_num);
    std::string binary_str = binary_bitset.to_string();

    // 去除字符串前导零
    size_t non_zero_pos = binary_str.find_first_not_of('0');
    binary_str = binary_str.substr(non_zero_pos);

    std::cout << "Binary: " << binary_str << std::endl;

    return 0;
}

通过上述示例,我们可以学会如何在C/C++中实现二进制与十进制之间的转换。接下来,我们将介绍如何在二进制与十六进制之间进行转换。

3.2.3 二进制与十六进制互转 (Binary and Hexadecimal Conversion)

在C/C++编程中,要实现二进制与十六进制之间的转换,我们可以使用一些标准库函数和流操作进行转换。

以下是具体的转换示例:

  • 二进制转十六进制:
#include <iostream>
#include <bitset>
#include <sstream>

int main() {
    std::string binary_str = "101010";
    std::bitset<32> binary_bitset(binary_str);
    std::stringstream hex_ss;

    // 将二进制字符串转换为对应的十进制整数
    unsigned long decimal_num = binary_bitset.to_ulong();

    // 将十进制整数转换为十六进制字符串
    hex_ss << std::hex << decimal_num;
    std::string hex_str = hex_ss.str();
    std::cout << "Hexadecimal: " << hex_str << std::endl;

    return 0;
}
  • 十六进制转二进制:
#include <iostream>
#include <bitset>
#include <sstream>

int main() {
    std::string hex_str = "2A";
    int decimal_num;

    // 将十六进制字符串转换为十进制整数
    std::istringstream(hex_str) >> std::hex >> decimal_num;

    // 将十进制整数转换为二进制字符串
    std::bitset<32> binary_bitset(decimal_num);
    std::string binary_str = binary_bitset.to_string();

    // 去除字符串前导零
    size_t non_zero_pos = binary_str.find_first_not_of('0');
    binary_str = binary_str.substr(non_zero_pos);

    std::cout << "Binary: " << binary_str << std::endl;

    return 0;
}

通过上述示例,我们可以学会如何在C/C++中实现二进制与十六进制之间的转换。接下来,我们将介绍有关符号数进制转换的方法。

3.3 符号数进制转换 (Signed Number Base Conversion)

对于带符号数(signed numbers)的进制转换,我们需要考虑数值的符号以及处理负数时的二进制表示法(通常使用补码表示法)。以下是一些建议和示例以实现带符号数的进制转换。

注意:在负数二进制表示中,最高位(最左边)表示符号位,1表示负数,0表示正数。

  • 使用补码表示法转换正负数:

将一个负数转换为补码表示法,需要执行以下步骤:

  1. 将该负数转换为其绝对值的二进制形式。
  2. 将所得到的二进制数按位取反(将0变为1,将1变为0)。
  3. 在此基础上加1

例:将-5以补码形式表示为8位二进制数

1. 绝对值的二进制表示为:0000 0101
2. 按位取反得到:        1111 1010
3. 加1得到补码:          1111 1011
  • 负数的二进制转十进制:

要将负数的二进制转换为十进制,务必先将这个数从补码形式转换为其真实的十进制表示,然后根据符号位决定是否将十进制值设为负数。

以下是一个使用C++进行带符号数二进制与十进制转换的示例:

#include <iostream>
#include <bitset>
#include <cstdint>

int main() {
    std::string binary_str = "11111011"; // 补码形式表示的 -5
    std::bitset<8> binary_bitset(binary_str);

    // 将二进制字符串转换为对应的(有符号)十进制整数
    int8_t decimal_num = static_cast<int8_t>(binary_bitset.to_ulong());
    std::cout << "Decimal: " << static_cast<int>(decimal_num) << std::endl;

    return 0;
}

这些示例和建议可以帮助您更好地理解和实现带符号数的进制转换。在实际编程中,请根据自己的需求选择合适的方法和函数。在处理有符号数时,请务必注意数值的范围以避免溢出。

3.4 符号数进制转换的数学方法

在将带符号数进行进制转换时,我们需要首先确定符号位。对于负数,需要采用补码表示。在接下来的部分中,我将提供数学方法以实现各种进制之间的转换。

以二进制和十进制间互转为例:

正数

  1. 二进制转十进制:

例如,将二进制数 1101 转换为十进制时,按权展开:

(1 × 2^3) + (1 × 2^2) + (0 × 2^1) + (1 × 2^0) = 8 + 4 + 0 + 1 = 13。

  1. 十进制转二进制:

例如,将十进制数 13 转换为二进制时,执行连续除法:

13 ÷ 2 = 6 ...余 1
 6 ÷ 2 = 3 ...余 0
 3 ÷ 2 = 1 ...余 1
 1 ÷ 2 = 0 ...余 1

由此得到二进制数 1101。

负数

对于负数,首先将其绝对值转换为二进制,然后转换为补码表示。

例如,将 -13 转换为二进制:

  1. 将绝对值 13 转换为二进制:1101
  2. 按位取反(1 变为 0,0 变为 1):0010
  3. 加 1:0011,补码表示为 1111。

下面是将补码表示的负数从二进制转换为十进制的方法:

例如,将补码形式表示的二进制数 1111 转换为十进制数:

  1. 减 1:1110
  2. 按位取反:0001
  3. 按权展开:(0 × 2^3) + (0 × 2^2) + (0 × 2^1) + (1 × 2^0) = 1
  4. 添加负号,得到 -1。

对于八进制和十六进制与其他进制的转换,可以先将数值转换为二进制,然后再转换为目标进制。

3.5 小数点进制转换

对于小数部分,我们可以使用类似的方法进行进制转换。这里我们以二进制和十进制之间的互相转换为例:

小数:二进制转十进制

例如,将二进制小数 0.1101 转换为十进制小数:

按权展开:(1 × 2^-1) + (1 × 2^-2) + (0 × 2^-3) + (1 × 2^-4) = 0.5 + 0.25 + 0 + 0.0625 = 0.8125。

小数:十进制转二进制

例如,将十进制小数 0.8125 转换为二进制小数:

执行连续乘法,将乘法结果的整数部分一次提取出来,直到其结果为 0 或达到所需的精度:

0.8125 × 2 = 1.625 ...提取 1
0.6250 × 2 = 1.250 ...提取 1
0.2500 × 2 = 0.500 ...提取 0
0.5000 × 2 = 1.000 ...提取 1

将提取的整数部分依次排列:1101;从而得到二进制小数 0.1101。

对于小数部分的八进制、十六进制与其他进制之间的转换,与上述过程类似。可以先将小数转换为二进制形式,然后再将其转换为目标进制。在实际应用中,注意控制所需的精度以避免无限循环小数的出现。

3.6 进制转换综述

下表总结了二进制、八进制、十进制和十六进制之间的数学转换方法与代码转换方法。

转换类型数学方法代码方法(C++)
二进制 -> 十进制按权展开求和使用 std::bitset 将二进制字符串转换为 unsigned long
十进制 -> 二进制连续除法求余使用 std::bitset 将整数转换为二进制字符串
八进制 -> 十进制按权展开求和使用 std::istringstream 将八进制字符串转换为整数
十进制 -> 八进制连续除法求余使用 std::stringstream 将整数转换为八进制字符串
十六进制 -> 十进制按权展开求和使用 std::istringstream 将十六进制字符串转换为整数
十进制 -> 十六进制连续除法求余使用 std::stringstream 将整数转换为十六进制字符串
符号数二进制 -> 十进制补码形式的逆过程求和使用 std::bitset 将补码形式的二进制字符串转换为整数
符号数十进制 -> 二进制按补码形式转换使用 std::bitset 将整数转换为补码形式的二进制字符串
小数二进制 -> 十进制按权展开求和使用类似按权展开的自定义实现
小数十进制 -> 二进制连续乘法求整数部分使用类似连续乘法的自定义实现

扩展内容:

  1. 符号数进制转换:处理负数时需要使用补码表示法。当转换负数的进制时,需先计算绝对值的目标进制表示,然后将其转换成补码形式。
  2. 小数的进制转换:对于小数部分,使用按权展开求和的方法(二进制 -> 十进制)以及连续乘法求整数部分的方法(十进制 -> 二进制)进行转换。对于小数部分的八进制、十六进制与其他进制之间的转换,可以先将小数转换为二进制形式,然后再将其转换为目标进制。注意控制所需的精度以避免无限循环小数的出现。

3.7 BaseConverter 类的实现

以下是一个 BaseConverter 类的实现,它具有所需的功能。

首先,定义一个结构体 NumberRepresentation 以存储各种进制的数值表示:

#include <string>
#include <iostream>
#include <sstream>
#include <bitset>

struct NumberRepresentation {
    std::string binary;
    std::string octal;
    std::string decimal;
    std::string hexadecimal;
};

然后,创建一个进制转换类 BaseConverter,实现所需的功能:

class BaseConverter {
public:
    NumberRepresentation convert(int number) {
        NumberRepresentation num_repr;
        num_repr.binary = int_to_binary(number);
        num_repr.octal = int_to_octal(number);
        num_repr.decimal = std::to_string(number);
        num_repr.hexadecimal = int_to_hex(number);
        return num_repr;
    }

    std::string hex_array_to_string(const uint8_t *hex_array, size_t size) {
        std::stringstream ss;
        ss << std::hex;
        for (size_t i = 0; i < size; ++i) {
            ss << static_cast<int>(hex_array[i]);
        }
        return ss.str();
    }

    // 提供数学转换接口,不使用C++ API
    int binary_to_decimal_math(const std::string& binary) {
        int decimal = 0;
        for (size_t i = 0; i < binary.length(); ++i) {
            decimal = decimal * 2 + (binary[i] - '0');
        }
        return decimal;
    }

    std::string decimal_to_binary_math(int decimal) {
        std::string binary;
        while (decimal > 0) {
            binary = std::to_string(decimal % 2) + binary;
            decimal /= 2;
        }
        return binary;
    }

    int octal_to_decimal_math(const std::string& octal) {
        int decimal = 0;
        for (size_t i = 0; i < octal.length(); ++i) {
            decimal = decimal * 8 + (octal[i] - '0');
        }
        return decimal;
    }

    std::string decimal_to_octal_math(int decimal) {
        std::string octal;
        while (decimal > 0) {
            octal = std::to_string(decimal % 8) + octal;
            decimal /= 8;
        }
        return octal;
    }

    int hexadecimal_to_decimal_math(const std::string& hex) {
        int decimal = 0;
        for (size_t i = 0; i < hex.length(); ++i) {
            char digit = hex[i];
            int value;
            if ('0' <= digit && digit <= '9') {
                value = digit - '0';
            } else if ('A' <= digit && digit <= 'F') {
                value = digit - 'A' + 10;
            } else if ('a' <= digit && digit <= 'f') {
                value = digit - 'a' + 10;
            } else {
                throw std::invalid_argument("Invalid hexadecimal character");
            }
            decimal = decimal * 16 + value;
        }
        return decimal;
    }

    std::string decimal_to_hexadecimal_math(int decimal) {
        const char* hex_digits = "0123456789ABCDEF";
        std::string hex;
        while (decimal > 0) {
            hex = hex_digits[decimal % 16] + hex;
            decimal /= 16;
        }
        return hex;
    }

    double binary_fraction_to_decimal_math(const std::string& binary_fraction) {
        double decimal = 0;
        double mult = 0.5;
        for (char ch : binary_fraction) {
            decimal += (ch - '0') * mult;
            mult *= 0.5;
        }
        return decimal;
    }

    std::string decimal_fraction_to_binary_math(double decimal_fraction, int precision) {
        std::string binary_fraction;
        while (precision > 0 && decimal_fraction > 0) {
            decimal_fraction *= 2;
            binary_fraction += (decimal_fraction >= 1) ? '1' : '0';
            if (decimal_fraction >= 1) {
                decimal_fraction -= 1;
            }
            --precision;
        }
        return binary_fraction;
    }

private:
    std::string int_to_binary(int number) {
        std::bitset<32> binary_bitset(number);
        std::string binary_str = binary_bitset.to_string();
        size_t non_zero_pos = binary_str.find_first_not_of('0');
        return binary_str.substr(non_zero_pos);
    }

    std::string int_to_octal(int number) {
        std::stringstream ss;
        ss << std::oct << number;
        return ss.str();
    }

    std::string int_to_hex(int number) {
        std::stringstream ss;
        ss << std::hex << number;
        return ss.str();
    }
};

现在,您可以使用这个类进行进制转换和其他相关任务。例如:

int main() {
    BaseConverter converter;
    int input_number = 42;
    NumberRepresentation num_repr = converter.convert(input_number);

    std::cout << "Binary: " << num_repr.binary << std::endl;
    std::cout << "Octal: " << num_repr.octal << std::endl;
    std::cout << "Decimal: " << num_repr.decimal << std::endl;
    std::cout << "Hexadecimal: " << num_repr.hexadecimal << std::endl;

    uint8_t hex_array[] = {0x74, 0x65, 0x73, 0x74};
    std::string hex_str = converter.hex_array_to_string(hex_array, sizeof(hex_array) / sizeof(uint8_t));
    std::cout << "Hexadecimal string: " << hex_str << std::endl;

    return 0;
}

在这个例子中,我们定义了一个结构体 NumberRepresentation 和一个进制转换类 BaseConverter,类中实现了所需的功能。类的方法可以为整数生成二进制、八进制、十进制和十六进制表示,将十六进制数组转换为字符串,以及提供数学转换接口(这些接口需要自行根据前述数学方法来实现)。

四、C/C++ 高级进制转换应用 (Advanced Base Conversion Applications in C/C++)

4.1 不同进制表示法的读写 (Reading and Writing in Different Base Representations)

在实际应用中,我们可能需要将不同进制的数值表示从文件、网络传输或其他源中读入,并将其转换为整数或浮点数以进行进一步处理。同样地,我们也可能需要将整数或浮点数转换为其他进制的形式,以便进行输出或传输。

读取

从文件或其他源中读取不同进制的表示时,需要了解该表示的格式。例如,二进制前面通常有 “0b” 或 “0B” 前缀,八进制有 “0” 前缀,十六进制有 “0x” 或 “0X” 前缀。读取过程中需忽略这些前缀,并将后续的字符读入字符串或字符数组进行进一步处理。

写入

写入不同进制表示时,通常需要为输出的字符串添加相应的前缀。添加前缀有助于在后续读取时识别不同的数值表示和进制。

4.2 使用位操作符进行进制转换 (Using Bitwise Operators for Base Conversion)

4.2.1 位操作符与进制转换 (Bitwise Operators and Base Conversion)

位操作符允许我们直接操作整数的二进制位。这可以让我们高效地实现二进制与其他进制之间的转换。位操作符包括:按位与(&),按位或(|),按位异或(^),按位非(~),左移(<<),右移(>>)等。

在进制转换过程中,位操作符可以帮助我们直接访问和修改数值的二进制位,从而简化计算过程。例如,对于加法和乘法等基本运算,可以通过按位操作实现而无需真正执行加法和乘法。同时,在需要高效执行的场景中(如网络编程、加密算法等),位操作符在性能上的优势使得它成为实现进制转换等操作的首选。

在实际编程中,结合具体问题和项目需求,我们可以灵活选择是否使用位操作符。选择使用位操作符时需要考虑到代码的可读性和性能。在一些情况下,使用位操作符可以提高代码性能,但可能会降低代码可读性。在这种情况下,我们需要在性能与可读性之间进行权衡。

4.2.2 用位操作符实现的进制转换算法 (Base Conversion Algorithm using Bitwise Operators)

使用位操作符实现的进制转换算法与前述的除法和乘法运算相似。例如,将一个十进制整数转换为二进制字符串时,可以使用右移操作符逐位读取整数的二进制表示:

std::string decimal_to_binary_bitwise(int decimal) {
    std::string binary;
    for (int i = 31; i >= 0; --i) {
        binary += ((decimal >> i) & 1) ? '1' : '0';
    }
    size_t non_zero_pos = binary.find_first_not_of('0');
    return binary.substr(non_zero_pos);
}

该函数首先创建一个空的二进制字符串。然后,从最高位(第31位)开始,逐位进行以下操作:使用右移操作符将当前位移动到二进制表示的最低位(第0位),然后用按位与操作符 & 和 1 进行按位与运算。这样可以得到当前位的值(0 或 1)。将这个值转换为字符并添加到二进制字符串中。

最后,使用 find_first_not_of 函数找到第一个不是 ‘0’ 的字符的位置,从该位置开始截取子字符串,以去除前导零。这样,我们使用位操作符实现了十进制整数到二进制字符串的转换。在实际应用中,还可以类似地使用位操作符实现其他进制间的转换。

4.2.3 实际应用案例 (Practical Application Cases)

在某些应用场景中,例如网络协议或加密技术等,位操作符特别适用。使用位操作符进行进制转换可以实现高效的算法,提高程序的性能。

案例1:网络协议

许多网络协议(如 IPv4、IPv6 或 TCP/IP 等)在传输数据时需要操作二进制位。在这些场景中,位操作符可以实现高效的算法,达到更好的性能。

例如,IPv4 地址通常表示为 4 个十进制整数(每个范围在 0-255 之间),用英文句点分隔。但在实际中,IPv4 地址是 32 位的二进制整数。使用位操作符可以方便地在二进制和点分十进制之间进行转换。例如,IP 地址子网掩码的计算就需要用到位操作符。

案例2:加密技术

在加密技术中,密钥和明文往往需要进行位级别的操作以产生密文。例如,DES(Data Encryption Standard)加密算法中,在密钥生成和加密过程中大量使用了位操作符。进行置换、选择、异或等操作时,位操作符可以简化实现过程,提高计算速度。

通过这些实际应用案例,可以看到位操作符在进制转换以及其他处理二进制位的场景中具有明显的性能优势。在性能敏感的场合,使用位操作符进行进制转换和其他二进制位操作是一个理想的选择。同时,我们需要权衡代码的可读性和性能,因此在不同的场景下,我们可以根据需要灵活地选择使用位操作符或其他方法。

4.3 利用C++ 标准库中的进制转换功能 (Using Base Conversion Functions in C++ Standard Library)

C++ 标准库提供了一些实用功能,可帮助我们进行进制转换。例如,可以使用 <bitset> 处理二进制字符串,<sstream> 实现进制间的转换等。比如以下示例:

例1: 使用 bitset 处理二进制字符串

#include <bitset>

std::string int_to_binary(int integer) {
    std::bitset<32> binary_bitset(integer);
    return binary_bitset.to_string();
}

在这个例子中,我们将整数转换为一个包含 32 位的 bitset。接着,我们使用 bitsetto_string() 函数将其转换为二进制字符串。需要注意的是,bitset::to_string() 生成的字符串可以包含前导零,根据需求可以选择进一步处理结果。

例2: 使用 stringstream 实现进制间的转换

#include <sstream>
#include <iomanip>

int hex_to_decimal(const std::string& hexadecimal) {
    int decimal;
    std::stringstream ss(hexadecimal);
    ss >> std::hex >> decimal;
    return decimal;
}

在此示例中,我们将十六进制字符串转换为十进制整数。首先,我们创建一个 stringstream 对象并将十六进制字符串输入其中。然后使用 std::hex 修饰符指定我们将从 stringstream 读取十六进制整数。最后,通过将 stringstream 对象转换为整数,实现进制间的转换。

在实际项目中,可以根据性能需求和代码可读性来决定是使用位操作符实现进制转换,还是使用 C++ 标准库中提供的功能。在很多情况下,使用 C++ 标准库的功能具有良好的代码可读性,且性能足够满足需求。

五、进制转换相关面试题

本章将提供一些针对进制转换的面试题。这些题目主要分为以下几个部分:

5.1 基本进制转换题目

这部分面试题主要测试对进制转换基本概念的理解和基本编程能力。

面试题1:将给定的十进制整数转换为二进制字符串

问题描述:给定一个非负整数 n,要求将其转换为二进制字符串。

要求:

  • 写一个函数 string decimal_to_binary(int n),输入为非负整数 n,输出为二进制字符串。

示例:

输入: 2
输出: "10"

输入: 10
输出: "1010"

面试题2:将给定的十进制整数转换为十六进制字符串

问题描述:给定一个整数 n,要求将其转换为十六进制字符串。注意:负整数应当用补码表示。

要求:

  • 写一个函数 string decimal_to_hex(int n),输入为整数 n,输出为十六进制字符串。

示例:

输入: 26
输出: "1A"

输入: -1
输出: "FFFFFFFF"

面试题3:将给定的二进制字符串转换为十进制整数

问题描述:给定一个二进制字符串 s,要求将其转换为十进制整数。

要求:

  • 写一个函数 int binary_to_decimal(const string &s),输入为二进制字符串 s,输出为十进制整数。

示例:

输入: "11010"
输出: 26

输入: "1010"
输出: 10

5.2 复杂进制转换题目

这部分面试题较复杂,测试在实际应用中处理较为复杂的进制转换问题的能力。

面试题4:计算两个二进制字符串的和

问题描述:给定两个二进制字符串 a 和 b,返回它们的和(用二进制表示)。

要求:

  • 写一个函数 string add_binary(const string &a, const string &b),输入为两个二进制字符串 a 和 b,输出为它们的和(二进制表示)。

示例:

输入: a = "1010", b = "110"
输出: "10000"

面试题5:将 IPv4 地址从十进制点分表示法转换为二进制表示

问题描述:给定一个有效的 IPv4 地址 ip,使用点分十进制格式表示。请实现一个函数,将给定的 IPv4 地址从十进制点分表示法转换为 32 位二进制整数表示。

要求:

  • 写一个函数 uint32_t ipv4_decimal_to_binary(const string &ip),输入为一个表示 IPv4 地址的字符串,输出为 32 位二进制整数。

示例:

输入: ip = "192.168.1.1"
输出: 3232235777

面试题6:计算汉明距离

问题描述:给定两个整数 x 和 y,计算它们的汉明距离。汉明距离(Hamming distance)是相应位置上二进制数值不同的位数。

要求:

  • 写一个函数 int hamming_distance(int x, int y),输入为两个整数 x 和 y,输出为它们的汉明距离。

示例:

输入: x = 1, y = 4
输出: 2
原因:
1   (0 0 0 1)
4   (0 1 0 0)
       ↑   ↑

5.3 进制转换与其他技术结合的题目

这部分面试题将进制转换与其他领域(如数据结构、算法等)相结合,测试在实际项目中处理更加负责的问题的能力。

面试题7:二叉树中根到叶路径的二进制求和

问题描述:给定一个由 0 和 1 组成的二叉树,每个根到叶路径表示一个二进制数。从上到下遍历,指定的一个路径构成的二进制数,请计算所有路径的和。

要求:

  • 给定树的根结点,请写一个函数 int sum_root_to_leaf(TreeNode* root),输入为二叉树的根节点,输出为所有二进制路径和。

示例:

输入:
    1
   / \
  0   1
 / \ / \
1  0 0  1

输出: 22
解释:
(100)1 + (101)5 + (110)6 + (111)7 = 22

面试题8:验证 UTF-8 编码

问题描述:UTF-8 是一种变长字节编码,用于表示 Unicode 编码的字符。请验证给定的字节数组是否表示有效的 UTF-8 编码。

要求:

  • 写一个函数 bool is_valid_utf8(const vector<int>& data),输入为表示字节的整数数组,输出为布尔值,表示输入是否为有效的 UTF-8 编码。

示例:

输入: data = [197, 130, 1]
输出: true
解释: 这是有效的 UTF-8 编码,表示字母 "ć"(U+0107)。

面试题9:数字与字母的相互转换

问题描述:给定一个整数,实现整数与字母之间的相互转换。从 1 开始,分别表示字母 A 到 Z。例如,1 对应 A,2 对应 B,…,26 对应 Z。要求不使用任何库函数。

要求:

  • 写两个函数 string int_to_alpha(int n)int alpha_to_int(const string& s),分别将整数转换为字母字符串和将字母字符串转换为整数。

示例:

输入: 28
输出: "AB"

输入: "AB"
输出: 28

5.4 面试题答案

面试题1:将给定的十进制整数转换为二进制字符串

string decimal_to_binary(int n) {
    if (n == 0) {
        return "0";
    }
    string result;
    while (n > 0) {
        result = (n % 2 ? '1' : '0') + result;
        n /= 2;
    }
    return result;
}

面试题2:将给定的十进制整数转换为十六进制字符串

string decimal_to_hex(int n) {
    if (n == 0) {
        return "0";
    }
    const char* hex_digits = "0123456789ABCDEF";
    string result;
    for (int i = 7; i >= 0; --i) {
        result += hex_digits[(n >> (i * 4)) & 0xf];
    }
    size_t non_zero_pos = result.find_first_not_of('0');
    return result.substr(non_zero_pos);
}

面试题3:将给定的二进制字符串转换为十进制整数

int binary_to_decimal(const string &s) {
    int result = 0;
    for (const char c : s) {
        result = result * 2 + (c - '0');
    }
    return result;
}

面试题4:计算两个二进制字符串的和

string add_binary(const string &a, const string &b) {
    string result;
    int i = a.size() - 1, j = b.size() - 1;
    int carry = 0;
    while (i >= 0 || j >= 0) {
        int sum = carry + (i >= 0 ? a[i--] - '0' : 0) + (j >= 0 ? b[j--] - '0' : 0);
        result = (sum % 2 ? '1' : '0') + result;
        carry = sum / 2;
    }
    if (carry) {
        result = '1' + result;
    }
    return result;
}

面试题5:将 IPv4 地址从十进制点分表示法转换为二进制表示

uint32_t ipv4_decimal_to_binary(const string &ip) {
    uint32_t result = 0;
    int num = 0, count = 0;
    for (const char c : ip) {
        if (c == '.') {
            result = (result << 8) | num;
            num = 0;
            ++count;
        } else {
            num = num * 10 + (c - '0');
        }
    }
    result = (result << 8) | num;
    return result;
}

面试题6:计算汉明距离

int hamming_distance(int x, int y) {
    int xor_result = x ^ y;
    int distance = 0;
    while (xor_result) {
        distance += xor_result & 1;
        xor_result >>= 1;
    }
    return distance;
}

面试题7:二叉树中根到叶路径的二进制求和

int sum_path(TreeNode* node, int path_val) {
    path_val = (path_val << 1) | node -> val;
    if (!node -> left && !node -> right) {
        return path_val;
    }
    int total_sum = 0;
    if (node -> left) {
        total_sum += sum_path(node -> left, path_val);
    }
    if (node -> right) {
        total_sum += sum_path(node -> right, path_val);
    }
    return total_sum;
}

int sum_root_to_leaf(TreeNode* root) {
    if (!root) {
        return 0;
    }
    return sum_path(root, 0);
}

面试题8:验证 UTF-8 编码

bool is_valid_utf8(const vector<int>& data) {
    int n_bytes = 0;
    for (int byte : data) {
        if (n_bytes == 0) {
            if (byte >> 5 == 0b110) n_bytes = 1;
            else if (byte >> 4 == 0b1110) n_bytes = 2;
            else if (byte >> 3 == 0b11110) n_bytes = 3;
            else if (byte >> 7 != 0) return false;
        } else {
            if (byte >> 6 != 0b10) return false;
            n_bytes--;
        }
    }
    return n_bytes == 0;
}

面试题9:数字与字母的相互转换

string int_to_alpha(int n) {
    if (n <= 0) {
        return "";
    }
    string result;
    while (n > 0) {
        result = char('A' + (n - 1) % 26) + result;
        n = (n - 1) / 26;
    }
    return result;
}

int alpha_to_int(const string& s) {
    int result = 0;
    for (const char c : s) {
        result = result * 26 + (c - 'A' + 1);
    }
    return result;
}

六、结论与展望

经过前五章的学习,我们发现进制转换不仅是编程领域中的基础知识,而且对提高逻辑思维能力和解决实际问题具有很大的帮助。从心理学的角度来看,掌握进制转换原理以及相关应用不仅有助于提升对数学思维的理解,还有利于培养求知欲和语言表达能力。

通过本博客所涉及的实例和面试题,我们可以看到进制转换在计算机科学领域中具有广泛的应用,涉及数据结构、网络编程、编码等多个方面。不论是用于工作还是面试,这些知识点都会为你带来独特的优势。同时,编程面试中出现的进制转换相关问题往往需要在有限的时间内找到合适的解决方案,因此从心理学的角度来说,这些问题具有挑战性,有助于锻炼思维能力和建立心理承受压力的机制。

在未来的工作与学习中,我们相信掌握好进制转换技能将在各个领域产生深远的影响。在本博客的学习过程中,希望大家积极参与讨论,增进共同的理解,并将所学应用到实际问题中。同时,我们期待你将所学到的知识和面试题应用于实际项目中,为计算机科学发展做出更多的贡献。

感谢你的阅读与支持!如果你觉得这篇博客对你的学习有所帮助,欢迎点击收藏并点赞。期待我们在学习的道路上相互激励,共同成长!如有任何问题和建议,欢迎在评论区留言讨论,我们将尽快回复。再次感谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

探索C/C++ 进制转换之美:从原理到应用 的相关文章

  • 十大经典排序算法总结(C语言版本)

    前言 xff1a 排序算法 是最经典的算法知识 xff0c 也是每个合格程序员应该需要掌握的知识点 考虑到排序算法通常代码简短 xff0c 逻辑思维强和应用范围广等特性 xff0c 排序算法题目便成为了面试中的常客 在面试中最常考的是快速排
  • Unicode、UTF-8、UTF-16 终于懂了

    计算机起源于美国 xff0c 上个世纪 xff0c 他们对英语字符与二进制位之间的关系做了统一规定 xff0c 并制定了一套字符编码规则 xff0c 这套编码规则被称为ASCII编码 ASCII 编码一共定义了128个字符的编码规则 xff
  • Prometheus 的优雅关闭

    1 方法1 xff1a 用 pgrep f prometheus 找到运行的 Prometheus 进程号 使用 kill TERM 1234 来关闭 2 方法2 需要通过 web enable lifecycle 参数开启 lifecyc
  • Ceph运维操作

    1 操控集群 1 1 UPSTART Ubuntu系统下 xff0c 基于ceph deploy部署集群后 xff0c 可以用这种方法来操控集群 列出节点上所有Ceph进程 xff1a start ceph all 启动节点上特定类型的Ce
  • k8s部署Ceph

    1 Helm部署 1 1 简介 为了将Ceph部署到K8S集群中 xff0c 可以利用ceph helm项目 目前此项目存在一些限制 xff1a public和cluster网络必须一样如果Storage的用户不是admin xff0c 你
  • Ceph性能调优

    1 最佳实践 1 1 基本 监控节点对于集群的正确运行非常重要 xff0c 应当为其分配独立的硬件资源 如果跨数据中心部署 xff0c 监控节点应该分散在不同数据中心或者可用性区域日志可能会让集群的吞吐量减半 理想情况下 xff0c 应该在
  • Ceph常见问题

    1 CephFS问题诊断 1 1 无法创建 创建新CephFS报错Error EINVAL pool rbd ssd already contains some objects Use an empty pool instead xff0c
  • 镜像仓库 Harbor 对接 MinIO 对象存储

    Harbor 的部署之前使用的存储是 NFS xff0c 虽然可以使用 rsync 43 inotify 做数据同步做解决单点问题 xff0c 但是 NFS 效率 性能有限 xff0c 没有对象存储那么强大 xff0c 所以一般使用对象存储
  • thanos prometheus 的高可用、长期存储二进制部署

    1 简介 http thanos io thanos 是具有长期存储功能的开源 高可用性 Prometheus的集群组件 全局查询视图 跨多个 Prometheus 服务器和集群查询指标 无限保留 使用对象存储扩展系统 xff0c 不限时间
  • prometheus基本介绍

    001 基本介绍 1 主要功能 多维数据模型 xff08 时序由metric名字和k v的labels构成 xff09 灵活的查询语句无依赖存储 xff0c 支持local和remote不同的模型采用http协议 xff0c 使用pull模
  • prometheus基本概念

    基本概念 1 数据模型 prometheus存储的是时序数据 xff0c 即按照相同时序 xff08 相同名字和标签 xff09 xff0c 以时间维度存储的连续数据集合 时序是由名字以及key value标签定义 xff0c 具有相同的名
  • prometheus标签

    004 标签 1 作用 Prometheus中存储的数据为时间序列 xff0c 是由Metric的名字和一系列的标签 键值对 唯一标识的 不同的标签代表不同的时间序列 xff0c 即 通过指定标签查询指定数据 指标 43 标签实现了查询条件
  • 基于FreeRTOS的CPU利用率计算教程详解(STM32版)

    前言 xff1a FreeRTOS 是一个 RTOS 类的嵌入式实时操作系统 xff0c 作为实时操作系统其必定拥有任务调度的属性 通过系统自身的任务调度算法实现任务安全且高效的切换 xff0c 这就不可避免的引出了各个任务对 CPU 的利
  • kubelet残留孤儿pod(Orphaned pod)无法删除

    记录kubelet残留孤儿pod Orphaned pod 无法删除的问题分析和解决方法 问题 查看kubelet日志 xff0c 错误信息如下 xff1a E0823 10 31 01 847946 1303 kubelet volume
  • kubelet无法启动:more than 8 NUMA Nodes

    现象 xff1a kubelet启动报错 unsupported on machines with more than v NUMA Nodes 原因 xff1a maxAllowableNUMANodes specifies the ma
  • openshfit etcd备份恢复

    1 找到etcd的leader节点 xff1a 随机进入一个etcd的pod xff1b 使用 etcdctl endpoint status xff0c 返回值有true的就是etcd leader节点 2 进入etcd leader节点
  • 性能调优之 ETCD

    磁盘 IOPS 调整 etcd 对磁盘写入延迟非常敏感 xff0c 通常需要 50 顺序写入 IOPS 例如 7200RPM 磁盘 对于负载较重的集群 xff0c 建议使用 500 顺序写入 IOPS 例如 xff0c 典型的本地 SSD
  • etcd概述

    本文主要介绍了 etcd 相关概念 xff0c 以及 etcd 的主要使用场景 1 介绍 etcd 是云原生架构中的基础组件 xff0c 由 CNCF 孵化托管 etcd 在微服务和 kubernetes 集群中不仅可以作为服务注册中心用于
  • etcd启动过程梳理

    源码地址 xff1a https github com etcd io etcd 1 入口 scripts build sh run build echo Running 34 1 34 if 1 then log success 34 S

随机推荐

  • etcd v3使用示例

    1 简单使用 1 1 增加 set 指定某个键的值 例如 etcdctl span class token builtin class name set span testdir testkey span class token strin
  • 解决Docker运行命令时提示“Got permission denied while trying to connect to the Docker daemon socket“

    参考自 xff1a 公众号 xff1a 写bug的程旭源 问题截图 原因 xff1a docker守护进程启动的时候 xff0c 会默认赋予名字为docker的用户组读写Unix socket的权限 方法1 xff1a 使用sudo获取管理
  • CAN 读取ACK知对方是否接收成功

    首先 xff0c 了解一下CAN的ACK段 上图是一个数据帧 xff0c 其ACK段用来确认是否正常接收 由 ACK 槽 ACK Slot 和 ACK 界定符 2 个位构成 当发送单元发送到CRC段后 xff0c 会在ACK段发送2个隐性位
  • C++使用json在Linux中实现TCP通信

    最近在学习使用json格式在Linux中进行tcp通信 以下为学习笔记 我使用的第三方库为nlohomann json 仓库地址为 nlohmann json JSON for Modern C 43 43 github com nloho
  • C语言经典笔试题(一)

    1 请填写bool float 指针变量 与 零值 比较的if 语句 提示 xff1a 这里 零值 可以是0 0 0 FALSE 或者 空指针 例如int 变量n 与 零值 比较的if 语句为 xff1a if n 61 61 0 if n
  • PCB学习笔记

    1 笔记 1 PCB屏幕变暗 xff0c 鼠标左键点空白处加ALT 2 TM默认改变所有错误 xff0c 变红色正常 3 PCB线默认电源和地30mil或者尽量粗 xff0c 其他根据引脚粗细 4 修改PCB过孔尺寸 xff0c PV快捷键
  • Java中this的用法总结

    Java的this用法 1 普通的直接引用 这种就不用讲了 xff0c this相当于是指向当前对象本身 2 xff0c 当局部 xff08 或者形参 xff09 变量和成员变量重名的时候 xff0c 在方法中使用this表示成员变量以示区
  • keil软件中按F12 无法跳转到函数、变量定义处

    keil中按F12无法跳转到定义 原因分析 xff1a 我们都习惯性在最开始建立项目目录会以中文命名 xff0c 导致有时候某些软件就出现奇怪问题 xff0c keil版本都比较高了 xff0c 所以有时会出现之前旧版本没有的问题 xff0
  • VSCode修改主题颜色

    参考 xff1a https jingyan baidu com article ea24bc3983f2b59b63b33144 html 步骤1 xff1a 使用vscode打开一个工程 xff0c 点击左下角的设置按钮 步骤2 xff
  • Linux 中的驱动开发的初学者体会

    Linux 中的驱动开发的初学者体会 很多年前 xff0c 心里就存下这样一个愿望 就是把Linux 的驱动开发搞清楚 但是一开始上上这样的开发难度天大了 xff0c 对着一堆的寄存器发愁 于是就从简单的STM8 xff0c PIC16FX
  • 串口助手SerialAide

    串口助手SerialAide 1 基础界面 2 描述 1 自动搜索串口 xff1b 2 接收数据可以进行十六进制和ASCII切换 3 接收和发送数据可以设置不用颜色显示 xff0c 方便查看 xff1b 4 可以使用多命令表进行循环发送 x
  • jetson nano的处理器架构

    jetson nano 的架构是 arm64 注意与 amd64 区分 比如安装 vscode 时 下载一个 deb 里面的 xff21 rm64 即可
  • Docker 部署clickhouse-server及添加用户配置密码

    前言 由于现在居家办公测试环境连接公司的clickhouse需要vpn连接太麻烦且速度很慢 xff0c 于是乎在测试机自己搭建clickhouse xff0c 废话不多说直接开始教程 容器clickhouse server配置 拉取clic
  • 把寄存器做成一个结构体,赋值初始地址后寄存器赋值的操作

  • CMake中文手册_target_link_libraries(3.26)

    cmake commands 7 cmake 命令 7 概述 此命令具有以下各小节详细介绍的多个签名 所有这些签名都具有以下通用形式 xff1a target link libraries 命名的 必须是由 add executable 或
  • 【STM32】UART串口通信无法通信问题(SSCOM)

    需要在target里面勾选上MicroLIB才能显示 然后要完全编译 xff0c 编译全部的代码 找到正确的串口号 然后就可以正常在SSCOM xff08 或其它软件 xff09 中显示了 如果需要学习STM32 UART通信方法请移步这个
  • CMake中文手册_target_sources(3.26)

    target sources xff08 xff09 新版本 3 1 将源文件添加到目标 target sources xff08 span class token operator lt span target span class to
  • QML信号与信号槽实践指南:轻松掌握现代软件开发的关键技术

    这里写目录标题 xff08 一 xff09 QML简介1 1 QML概述1 2 QML的基本语法1 3 QML与C 43 43 的交互 xff08 二 xff09 QML信号基本概念2 1 QML中的信号2 2 QML信号的作用与优势 xf
  • QML/Qt Quick anchors.fill 的使用

    目录标题 引言QML 和 Qt Quick锚布局的概念anchors fill 属性 QML 锚布局基础锚点属性 xff08 左 右 顶 底 xff09 使用独立的锚点属性设置元素间的布局关系中心锚点 xff1a 水平和垂直 深入了解 an
  • 探索C/C++ 进制转换之美:从原理到应用

    一 简介 Introduction 进制前缀表示整数常量示例转换库接口参数及返回值示例二进制0b 或 0B0b1010std bitset lt gt std bitset lt 8 gt binary 42 std bitset lt 8