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"就是ax16^3^+2x16^2^+dx16^1^+4x16^0^,但位移的方式要更高效简洁,如下图所示,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"));
}
相关推荐
~yY…s<#>1 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
EricWang13583 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
我是谁??3 小时前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
Mephisto.java3 小时前
【大数据学习 | kafka高级部分】kafka的优化参数整理
大数据·sql·oracle·kafka·json·database
希言JY4 小时前
C字符串 | 字符串处理函数 | 使用 | 原理 | 实现
c语言·开发语言
午言若4 小时前
C语言比较两个字符串是否相同
c语言
沐雪架构师4 小时前
mybatis连接PGSQL中对于json和jsonb的处理
json·mybatis
TeYiToKu6 小时前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
互联网打工人no16 小时前
每日一题——第一百二十四题
c语言
爱吃生蚝的于勒6 小时前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法