cJson之环境搭建(一) 在线搭建cJson项目环境
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"));
}