cJson之parse_hex4(三)

cJson之环境搭建(一) 在线搭建cJson项目环境

cJson之parse_number(二) 数字解析

parse_hex4就是解析4个16进制字符,比如把"12bc"变成0x12bc,这有啥用呢?它主要将UTF-16编码转化成UTF-8编码,UTF-16、UTF-8这样的编码格式在后面解析字符串时介绍,目前先聚焦这个转化的实现,下面是解析代码

arduino 复制代码
static unsigned parse_hex4(const unsigned char * const input)
{
    unsigned int h = 0;
    size_t i = 0;

    for (i = 0; i < 4; i++)
        {
        /* 解析数字*/
        if ((input[i] >= '0') && (input[i] <= '9'))
        {
        h += (unsigned int) input[i] - '0';
        }
        else if ((input[i] >= 'A') && (input[i] <= 'F'))
        {
        h += (unsigned int) 10 + input[i] - 'A';
        }
        else if ((input[i] >= 'a') && (input[i] <= 'f'))
        {
        h += (unsigned int) 10 + input[i] - 'a';
        }
        else /* invalid */
        {
        return 0;
        }
    if (i < 3)
    {
        /* shift left to make place for the next nibble */
        h = h << 4;
        }
    }
    return h;
}

parse_hex4函数主要做了两件数

  • 把字符转化成对应的数字,比如'1'->1 , 'A'->A
  • 通过位移把数字组合起来

字符转数字

字符本来就是由数字映射而来,所以是可以运算的,比如字符'0'对应的数字就是48,要转成数字0,直接减48就可以了,但没事谁还记个码表,不知道这个48也不要紧,直接减字符'0'也一样;后面大小写字母也一样,它们的基准是10,所以加个10就可以了

位移

一个16进制数字占4位,4个占16位,用32位的int类型存储是没问题的,对二进制不大熟悉的可以阅读从十进制到二进制

在解析得到数字之后,常规的方法是用这个数字乘以权重,比如"a2d4"就是ax163+2x162+dx161+4x160,但位移的方式要更高效简洁,如下图所示,32位二进制太长,下图省略了高位的0

CMakeLists文件的修改

根目录下的CMakeLists文件保持不变

scss 复制代码
cmake_minimum_required(VERSION 3.12)
project(cJson)
# 编译子文件夹的CMakeLists.txt
add_subdirectory(tests)

parse_hex.c是测试此函数的文件,随着测试文件的增多,tests目录下编译测试文件的CMakeLists就要修改

scss 复制代码
# 生成目标库文件,SHARED代表动态的,STATIC代表静态的
add_library(unity STATIC unity/src/unity.c)

#set 方法设置 (name values) 方便后面引用,values可能有多个
set(unity_tests parse_number parse_hex4)

# 批量处理测试文件
foreach(unity_test ${unity_tests})
    add_executable("${unity_test}" "${unity_test}.c")
    target_link_libraries("${unity_test}" unity)
endforeach()

编译方式和之前一样,在build文件下使用make命令, 然后进入tests目录,使用./parse_hex4运行测试用例

测试

parse_hex.c有两个用例,下面这个用例思路分两步

  • 将0到0xFFFF的数字格式化成字符串,这包含了所有的4位16进制字符。%.4x表示格式化的16进制字符长度4位,字母小写,%.4X表示字母大写,比如小写:0xabcd->"abcd",大写:0xabcd->"ABCD"
  • 再将构造的字符串使用parse_hex4函数解析回去,比较是否一致
arduino 复制代码
static void parse_hex4_should_parse_all_combinations(void)
{
    unsigned int number = 0;
    unsigned char digits_lower[6];
    unsigned char digits_upper[6];
    /* test all combinations */
    for (number = 0; number <= 0xFFFF; number++)
    {
    TEST_ASSERT_EQUAL_INT_MESSAGE(4, sprintf((char*)digits_lower, "%.4x", number), "sprintf failed.");
    TEST_ASSERT_EQUAL_INT_MESSAGE(4, sprintf((char*)digits_upper, "%.4X", number), "sprintf failed.");

    TEST_ASSERT_EQUAL_INT_MESSAGE(number, parse_hex4(digits_lower), "Failed to parse lowercase digits.");

    TEST_ASSERT_EQUAL_INT_MESSAGE(number, parse_hex4(digits_upper), "Failed to parse uppercase digits.");
    }
}

printf函数将格式化的字符串输出到屏幕,而sprintf函数将格式化的字符串输出到指定buffer中,比如上面的digits_lower数组,返回值是写入buffer中的字符串长度。

第二个用例验证了大小写混合的各种情况下是否正常

arduino 复制代码
static void parse_hex4_should_parse_mixed_case(void)
{
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"beef"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"beeF"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"beEf"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"beEF"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"bEef"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"bEeF"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"bEEf"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"bEEF"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"Beef"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BeeF"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BeEf"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BeEF"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEef"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEeF"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEEf"));
    TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEEF"));
}
相关推荐
草莓熊Lotso10 小时前
【洛谷题单】--分支结构(二)
c语言·c++·经验分享·其他·刷题
snowfoootball10 小时前
2025 蓝桥杯C/C++国B 部分题解
c语言·c++·笔记·学习·贪心算法·蓝桥杯
小立爱学习13 小时前
Linux 内存管理之page folios
linux·c语言
科大饭桶15 小时前
Linux系统编程Day9 -- gdb (linux)和lldb(macOS)调试工具
linux·服务器·c语言·c++
2301_7850381816 小时前
c++初学day1(类比C语言进行举例,具体原理等到学到更深层的东西再进行解析)
c语言·c++·算法
wtsolutions17 小时前
Batch Conversion Online JSON Files (from URL) to Excel by WTSolutions
json·excel·batch
babytiger17 小时前
我的c#用到Newtonsoft.Json.dll,Fleck.dll这两个dll能否打到一个exe 中,而不是一起随着exe拷贝
开发语言·c#·json
JasmineX-119 小时前
STM32的SPI通信(软件读写W25Q64)
c语言·stm32·单片机·嵌入式硬件
HW-BASE1 天前
《C语言》指针练习题--1
c语言·开发语言·单片机·算法·c
泽虞1 天前
数据结构与算法
c语言·数据结构·算法