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"));
}
相关推荐
草莓熊Lotso2 小时前
Linux 基础 IO 初步解析:从 C 库函数到系统调用,理解文件操作本质
linux·运维·服务器·c语言·数据库·c++·人工智能
梵刹古音2 小时前
【C语言】 字符数组相关库函数
c语言·开发语言·算法
2601_949146538 小时前
C语言语音通知API示例代码:基于标准C的语音接口开发与底层调用实践
c语言·开发语言
学嵌入式的小杨同学8 小时前
从零打造 Linux 终端 MP3 播放器!用 C 语言实现音乐自由
linux·c语言·开发语言·前端·vscode·ci/cd·vim
Aaron15889 小时前
基于RFSOC的数字射频存储技术应用分析
c语言·人工智能·驱动开发·算法·fpga开发·硬件工程·信号处理
爱编码的小八嘎10 小时前
C语言对话-21.模板特化,缺省参数和其他一些有趣的事情
c语言
yueyuexiaokeai111 小时前
linux kernel常用函数整理
linux·c语言
想放学的刺客12 小时前
单片机嵌入式试题(第29期)嵌入式系统的电源完整性设计与去耦电容选型。抗干扰设计与EMC合规性
c语言·stm32·嵌入式硬件·物联网·51单片机
集芯微电科技有限公司15 小时前
15V/2A同步开关型降压单节/双节锂电池充电管理IC支持输入适配器 DPM 功能
c语言·开发语言·stm32·单片机·嵌入式硬件·电脑
小高Baby@15 小时前
JSON、bind、form
数据结构·json