关于面向过程编程与指针的一些思考
长期以来,虽然有C语言的基础,但对C的使用主要停留在书面例子的基础上,没有复杂的功能和调用关系,因此,对面向过程的理解并不深刻。而使用java、js编写功能的时候,通常都是面向对象的思想。
在本例中,会有大量使用指针的场景,使得多个函数作用于同一个变量,C中没有成员函数的概念,函数是公有的,靠指针区别变量。这一点也让我有些不适应。
既然是一些思考,并没有刻意组织结构,会非常杂乱无章,请看到的朋友谅解。
在开始阅读教程的时候,函数与函数之间的调用、输出都感觉异常的别扭。下面逐步的分析下这个程序。如果有同道朋友看到了这篇博文,请配合摘要中github库的代码阅读。
程序主要做了哪些事?
在教程中,包含一个解析库,和一个单元测试,单元测试会统计:
- 执行了多少次测试
- 通过了多少次
- 通过率
- 返回一个标记
解析库是实际上执行解析动作的部分,主要包含:
- 根据json的标准去分析传入的字符串
- 根据不同的数据类型,讲解析后的结果放入json结构体
程序执行过程
单元测试是怎么工作的?
本教程中,单元测试主要包含一个基础的比较和信息输出函数(宏),以及一个在此基础上的不同形式的比较函数。 单元测试会调用实际的处理函数。
测试解析string类型json值的流程
test_parse_string函数
这个函数是测试分割string单元的入口:
static void test_parse_string() {
TEST_STRING("", "\"\"");
TEST_STRING("Hello", "\"Hello\"");
TEST_STRING是一个宏,这里只是替换下代码:
#define TEST_STRING(expect, json) \
do { \
lept_value v; \
lept_init(&v); \
EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json)); \
EXPECT_EQ_INT(LEPT_STRING, lept_get_type(&v)); \
EXPECT_EQ_STRING(expect, lept_get_string(&v), lept_get_string_length(&v)); \
lept_free(&v); \
} while (0)
注意在TEST_STRING函数的一开始,有一句lept_value v;
,这个变量会存在于整个解析过程中,使用指针对这个变量进行修改,而最终的结果,也在这个宏函数中进行比较。形参中的json
同理。面向过程编程中,数据和方法是分离的。
接下来是变量v
的初始化,对我来说,这显得有些无章法,调用一个函数,传给它一个变量的指针,对其做出修改,显然,这是C语言中常用的方式。
lept_parse_string函数
static int lept_parse_string(lept_context *c, lept_value *v) {
size_t head = c->top, len;
const char *p;
EXPECT(c, '\"');
p = c->json;
for (;;) {
char ch = *p++;
switch (ch) {
case '\"':
len = c->top - head;
lept_set_string(v, (const char *)lept_context_pop(c, len), len);
c->json = p;
return LEPT_PARSE_OK;
case '\0':
c->top = head;
return LEPT_PARSE_MISS_QUOTATION_MARK;
default:
PUTC(c, ch);
}
}
}
lept_parse_string
函数是实际上分割字符串的函数,主要做了这些事:
- 往栈中压入字符
- 错误检测与处理
- 将解析成功的字符串放入
lept_value *v
中
这个函数中仍然有很多疑难点,需要时刻牢记一点函数与数据是分离的,会有多个函数通过指针的方式对数据做出更改,因此关于这个函数第一句size_t head = c->top, len;
,head
就是为了记录更改前的c->top
的值,这一点应该是在设计的时候就确定的,遗憾的是我需要在后面需要用到的时候才想到。