Giter Site home page Giter Site logo

json-tutorial's People

Contributors

entropy2333 avatar imba-tjd avatar imdouyu avatar izackwu avatar miloyip avatar nov11 avatar relaxcn avatar rustberry avatar yongzhenpan avatar zwy4896 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

json-tutorial's Issues

double(浮点数比较大小)

浮点数不是不可以使用 “==”符号比较大小吗? 为什么这里使用这种比较方法也可行呢?

第二章第三问测试代码有问题

当把tutorial02/test.c中117行和120行去掉以后,在CLion中运行报错为
/Users/peng/Documents/json-tutorial-master/tutorial02/test.c:118: expect: 4 actual: 0 /Users/peng/Documents/json-tutorial-master/tutorial02/test.c:118: expect: 0 actual: 3 /Users/peng/Documents/json-tutorial-master/tutorial02/test.c:119: expect: 4 actual: 0 /Users/peng/Documents/json-tutorial-master/tutorial02/test.c:119: expect: 0 actual: 3
不知道为何会重复运行。

EXPECT_FALSE()宏有问题!

这样传参的话:EXPECT_FALSE(lept_get_boolean(&v))
lept_get_boolean() 正常情况下返回 LEPT_FALSE(1)
而宏展开则是 (actual) == 0,
应该是 (actual) == 1 才符合测试。

关于对3.1416几个数字解析不正确

解析3.1416解析出:
expect: 3.1415999999999999 actual: 3.1415999999999999
后面还有三组不正确,问题单步调试strtod解析错误,自己写了一个测试文件测试了,发现strtod解析3.1416正确,这是为什么呢?

我的是Ubuntu12 gcc4 .8.2

TUTORIAL02: 用于debug enum的宏

@miloyip
您好,
我在test.c里面加了两条用于DEBUG的宏。

test.c

#define EXPECT_EQ_RET(expect, actual) EXPECT_EQ_BASE((expect) == (actual), ret_e_name[expect], ret_e_name[actual], "%s")
#define EXPECT_EQ_TYPE(expect, actual) EXPECT_EQ_BASE((expect) == (actual), type_e_name[expect], type_e_name[actual], "%s")

然后把enum对应的名称数组放在了leptjson.h里面

leptjson.h

static const char* ret_e_name[] = {  
    "LEPT_PARSE_OK",
    "LEPT_PARSE_EXPECT_VALUE",
    "LEPT_PARSE_INVALID_VALUE",
    "LEPT_PARSE_ROOT_NOT_SINGULAR",
    "LEPT_PARSE_NUMBER_TOO_BIG"
};
static const char* type_e_name[] = {
    "LEPT_NULL",
    "LEPT_FALSE",
    "LEPT_TRUE",
    "LEPT_NUMBER",
    "LEPT_STRING",
    "LEPT_ARRAY",
    "LEPT_OBJECT"
};

我有一个疑问:

  1. 如果我加了static char* ret_e_name[] = ...,编译器会warn: var defined but not used(虽然现在没用use,但是以后可能会)。
  2. 如果直接写char* ret_e_name[] = ...,因为leptjson.h被两个文件同时include,LINK的时候会报错redefine。

我在想难道1就是正确的做法吗?通过编译选项把warning去掉?
我总感觉有其他漂亮的办法,希望您能解答。

缺少对堆栈top置零操作的测试?

LEPT_PARSE_INVALID_STRING_ESCAPE或LEPT_PARSE_INVALID_STRING_CHAR错误之后,若未将top置零,则可能assertion错误,但在测试中未能检测这一点。
是否需要增加这样的测试?

TEST_NUMBER(0.0, "1e-10000")

这个测试的结果会出现判断LEPT_PARSE_NUMBER_TOO_BIG的结果,做不到返回结果为0……
是有需要特殊处理的深意,还是本身不太正确?

tutorial02_answer中为什么指针暂存有着更好的性能。

原文

首先,如同 lept_parse_whitespace(),我们使用一个指针 p 来表示当前的解析字符位置。这样做有两个好处,一是代码更简单,二是在某些编译器下性能更好(因为不能确定 c 会否被改变,从而每次更改 c->json 都要做一次间接访问)。如果校验成功,才把 p 赋值至 c->json。

疑问

为什么使用p指针暂存有利于编译器优化,c->json的间接访问是什么意思?

数字校验是否有问题

 if (*p == '.') {
        p++;
        if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE;
        for (p++; ISDIGIT(*p); p++);
    }
    if (*p == 'e' || *p == 'E') {
        p++;
        if (*p == '+' || *p == '-') p++;
        if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE;
        for (p++; ISDIGIT(*p); p++);
    }

如果*p即不是.也不是e或者E 这时候数字也是非法的,比如字符串0m,但是这段代码没有处理这样的情况

这两种写法哪个比较好呢?

第一种是利用已经写好的函数, 意图更明显, 代码比较好懂, 但是性能可能会降低(?)

for ( i = 0; i < lept_get_array_size(v); i++)
                lept_free(lept_get_array_element(v, i));

第二种是直接操作, 这种代码看上去意图没有上面那种明显, 而且可能会出错, 但是作为库性能会更好

for (i = 0; i < v-> u.a.size;  i++)
                lept_free(&v->u.a.e[i]);

使用哪一种比较好呢?

T02,分享一下我的验证思路

做完第二部分练习时,对了一下参考答案,发现我的某部分实现可能会稍微短一些,和大家分享一下

  • 1.首先考虑第一个字符如果既不满足'0'~'9',又不是'-'号,那么就说明这是一个无效的数字。
  • 2.再考虑第一个字符是'0',但第二个字符既不是'.'也不是0(代表结束),同样也说明这是一个无效的数。
  • 3.然后,我们还需要解决末尾是'.'的情况,这时候,可以根据end指针的前一个位置的字符来判断,假设end[-1]是'.',说明这是小数点在末尾的情况,该数无效。(ps:这里不知道会不会出现_越界_的情况)
  • 4.最后就是数据过大或者数据过小的考虑了。参考叶老师给的strtod参考,使用errno的值来判断是否出现数据过大或者过小的情况,同时,数据过小时会取0,这是合法的,所以当发现errno值为ERANGE的时候,同时再判断数字的值是否是零,即可区分过大和过小。
static int lept_parse_number(lept_context* c, lept_value* v) {
    char* end;
    /* validate number */
    if( !ISDIGIT(c->json[0]) && c->json[0]!='-' ) return LEPT_PARSE_INVALID_VALUE;/* 1 */
    if( c->json[0]=='0' && c->json[1]!='.' && c->json[1]!=0 ) return LEPT_PARSE_ROOT_NOT_SINGULAR; /* 2 */
    v->n = strtod(c->json, &end);
    if (c->json == NULL || end[-1] == '.') /* end为小数点后的地址 */ /* 3 */
        return LEPT_PARSE_INVALID_VALUE;
    c->json = end; 
    if( errno == ERANGE && v->n != 0 ){ /* 4 */
        errno = 0;
        return LEPT_PARSE_NUMBER_TOO_BIG;
    }
    v->type = LEPT_NUMBER;
    return LEPT_PARSE_OK;
}

lept_encode_utf8 函数关于位操作处理疑问

叶老师请看注释

static void lept_encode_utf8(lept_context* c, unsigned u) {
    if (u <= 0x7F) 
        PUTC(c, u & 0xFF);
    else if (u <= 0x7FF) {
        PUTC(c, 0xC0 | ((u >> 6) & 0xFF)); // 这行最后为什么是 0xFF,为啥我觉得是 0x1F,即`11111`
        PUTC(c, 0x80 | ( u       & 0x3F));
    }
    else if (u <= 0xFFFF) {
        PUTC(c, 0xE0 | ((u >> 12) & 0xFF)); // 这行最后为什么是 0xFF,为啥我觉得是 0xF,即`1111`
        PUTC(c, 0x80 | ((u >>  6) & 0x3F));
        PUTC(c, 0x80 | ( u        & 0x3F));
    }
    else {
        assert(u <= 0x10FFFF);
        PUTC(c, 0xF0 | ((u >> 18) & 0xFF)); // 这行最后为什么是 0xFF,为啥我觉得是 0x7,即`111`
        PUTC(c, 0x80 | ((u >> 12) & 0x3F));
        PUTC(c, 0x80 | ((u >>  6) & 0x3F));
        PUTC(c, 0x80 | ( u        & 0x3F));
    }
}

我在做练习时,上面三处0xFF的地方写成我觉得的值,通过了测试。

Tutorial01 有些细节问题

宏的名字必须是唯一的,通常习惯以H_ 作为后缀。由于 leptjson 只有一个头文件,可以简单命名为 LEPTJSON_H__。如果项目有多个文件或目录结构,可以用 项目名称目录文件名称H_ 这种命名方式。

这里 Markdown 语法自动把两个 _ 变成斜体了,所以显示有点错误~

字符串解析\u0000应该如何处理?

比如test中的例子: "\"Hello\\u0000World\""
然而因为我们用char*存储字符串,所以虽然写进内存的是"Hello\0world",但是因为'\0'是终止符,那么只能得到"Hello"。
我自己使用c++实现了一下,使用std::string保存的字符串,最后得到的字符串是"Helloworld",`std::string``并没有遇到'\0'而终止。
我想问一下,在json语法中,这种情况是如何规定的呢?最终我们应该得到的字符串应该是哪一个呢?

第三单元解析字符串 realloc 可能分配失败的问题

static void* lept_context_push(lept_context* c, size_t size) {
    void* ret;
    assert(size > 0);
    if (c->top + size >= c->size) {
        if (c->size == 0)
            c->size = LEPT_PARSE_STACK_INIT_SIZE;
        while (c->top + size >= c->size)
            c->size += c->size >> 1;  /* c->size * 1.5 */
        c->stack = (char*)realloc(c->stack, c->size);
    }
    ret = c->stack + c->top;
    c->top += size;
    return ret;
}

一旦 realloc 分配失败,返回 NULL。c->stack 赋值为 NULL,之前 c->stack 指向的内存未释放。是不是需要加一个逻辑判断内存分配是否正常。

void* new_ptr = (char*)realloc(c->stack, c->size);
if (!new_ptr) {
    // 错误处理
}
c->stack = new_ptr;

CMake Error

起始项目的时候遇到:
goudandeMacBook-Pro:mini-JSON goudan$ cmake -DCMAKE_BUILD_TYPE=Debug ..
CMake Error: The source directory "/Users/kivygogh" does not appear to contain CMakeLists.txt.

/Users/kivygogh是我的根目录,第一次接触cmake,有点不知所以,求教作者大神原因?:)

lept_parse函数中在处理后续的空白时应该加上 v->type = LEPT_NULL;

if (*c.json != '\0') {
            v->type = LEPT_NULL;  //应该加上这一行
            ret = LEPT_PARSE_ROOT_NOT_SINGULAR;
        }

因为在test_parse_root_not_singular()函数中测试的刚好是

EXPECT_EQ_INT(LEPT_PARSE_ROOT_NOT_SINGULAR, lept_parse(&v, "null x"));

所以如果解析错误了, 后续的

EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));

测试还是可以通过, 如果增加新的测试, 比如

EXPECT_EQ_INT(LEPT_PARSE_ROOT_NOT_SINGULAR, lept_parse(&v, "false a"));

就无法通过了.

Tutorial01_answer中的一个小问题

if (*c.json != '\0')
    ret = LEPT_PARSE_ROOT_NOT_SINGULAR;

这里c并不是指针,为什么要加* 而且我去掉_能make通过。
请问这里加_没问题吗?刚开始学,不太懂。

关于boolean类型访问函数的疑惑

int lept_get_boolean(const lept_value* v) {
assert(v != NULL && (v->type == LEPT_TRUE || v->type == LEPT_FALSE));
return v->type == LEPT_TRUE;
}

void lept_set_boolean(lept_value* v, int b) {
lept_free(v);
v->type = b ? LEPT_TRUE : LEPT_FALSE;
}

为什么不直接用LEPT_TRUE, LEPT_FALSE 这两个类型作为返回值呢?

堆栈的push操作为何需要PUTC宏

请问,为什么lept_context_push要设计成返回一个指针,然后配合PUTC宏实现push操作;而不是直接将要push的内容作为参数传入lept_context_push中,在函数里完成操作?

是否采用有限状态机解析数字会更好?

这里我有一个自己实现的状态机,test.c中的所有测试均已通过。

首先定义状态:

typedef enum { INIT, SIGN, INT, POINT, FRAC, FRACNUM, EXPSIGN, EXP, END } NUM_PARSE_STATE;

接下来是解析:

static int lept_parse_number(lept_context* c, lept_value* v) {
    const char* p = c->json;
    NUM_PARSE_STATE state = INIT;
    for(;*p != '\0';p++){
        switch (state) {
            case INIT:
                if(*p == '-') state = SIGN; 
                else if (*p == '0') state = POINT;
                else if(ISDIGIT1TO9(*p)) state = INT;
                else return LEPT_PARSE_INVALID_VALUE;
                break;
            case SIGN:
                if(ISDIGIT1TO9(*p)) state = INT;
                else if (*p == '0') state = POINT;
                else return LEPT_PARSE_INVALID_VALUE;
                break;
            case INT:
                if (ISDIGIT(*p)) state = INT;
                else if (*p == '.') state = FRAC;
                else if (*p == 'e' || *p == 'E') state = EXPSIGN;
                else return LEPT_PARSE_INVALID_VALUE;
                break;
            case POINT:
                if (*p == '.') state = FRAC;
                else if (*p == 'e' || *p == 'E') state = EXPSIGN;
                else return LEPT_PARSE_ROOT_NOT_SINGULAR; //这里也应该是INVALID_VALUE,只是为了通过测试改成了NOT_SINGULAR
                break;
            case FRAC:
                if (ISDIGIT(*p)) state = FRACNUM;
                else return LEPT_PARSE_INVALID_VALUE;
                break;
            case FRACNUM:
                if (ISDIGIT(*p)) state = FRACNUM;
                else if (*p == 'e' || *p == 'E') state = EXPSIGN;
                else return LEPT_PARSE_INVALID_VALUE;
                break;
            case EXPSIGN:
                if (ISDIGIT(*p) || *p == '+' || *p == '-') state = EXP;
                else return LEPT_PARSE_INVALID_VALUE;
                break;
            case EXP:
                if (ISDIGIT(*p)) state = EXP;
                else return LEPT_PARSE_INVALID_VALUE;
                break;
            default: return LEPT_PARSE_INVALID_VALUE;
        }
    }
    if (state != INT && state != POINT && state != FRACNUM && state != EXP)
        return LEPT_PARSE_INVALID_VALUE;
    errno = 0;
    v->n = strtod(c->json, NULL);
    if (errno == ERANGE && (v->n == HUGE_VAL || v->n == -HUGE_VAL)) return LEPT_PARSE_NUMBER_TOO_BIG;
    v->type = LEPT_NUMBER;
    c->json = p;
    return LEPT_PARSE_OK;
}

Tutorial 4 `lept_parse_hex4(const char* p, unsigned* u) `

lept_parse_hex4(const char* p, unsigned* u) 中循环条件应该改成 for (i = 0; i < 4 && p; ++i),判断 p 不为 NULL
p只剩4个字符的情况下,即使parse的hex是有效的,但是也返回NULL,感觉并不是很合适。

不好意思,当时理解错了

小数比较直接使用“==”为何可行?

叶老师好,在比较double类型的宏实现中
#define EXPECT_EQ_DOUBLE(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%.17g")
一般浮点数比较不能直接像整数一样,还是说在给定的测试用例下可以用此方式?因为expect保存在内存中的值就是会和转换后的actual完全一样的?

TUTORIAL02: 练习二边界值测试

@miloyip
边界值测试我尝试从 float.h 拿出了一些边界值进行测试。
我用了一个宏来把 float.h 里面的宏转换成字符串

#include <float.h>
#define NUM_TO_STR(num_macro) (sprintf(buffer, "%.17g", num_macro))
...
static void test() {
    char buffer[100];
    NUM_TO_STR(FLT_MIN);
    TEST_NUMBER(FLT_MIN, buffer);
    // the same with FLT_EPSILON, FLT_MAX, DBL_MIN, DBL_EPSILON, DBL_MAX
    // -FLT_MIN, -FLT_EPSILON, -FLT_MAX, -DBL_MIN, -DBL_EPSILON, -DBL_MAX
}

有几个问题请教

  1. sprinf里面的格式,%17g在我测试的12个值里面是一个暂时安全的值。
  2. buffer的长度100看起来是安全的。
  3. 这样实现对不同的编译器兼容吗?对不同的OS兼容吗?

1.2.这两个地方我觉得很ugly,有其他好的实现方法吗。
3..我感觉比较不安全的样子。

谢谢你的解答。

字符串解析测试用例test_parse_invalid_string_escape()的疑问

叶老师你好,在解析字符串单元,static void test_parse_invalid_string_escape()函数中,认为""\v"" 这样的字符串是LEPT_PARSE_INVALID_STRING_ESCAPE,但是我认为这样转换后是实际字符串是“\v”,有效,因为有两个back slash,可以解释为‘\’,然后之后任意字符没有问题。
如果是""\v"",这样的确是有问题的。
我认为用例中应该去掉一个斜杠。参见:
string parse flow

函数static的作用?

请问:
为什么项目里的函数大多声明为static的?这样做有什么好处?
以及,一般在什么情况下将函数声明为static的,什么情况下作为普通函数?

regex无法匹配带小数点的数字

在校验JSON number是否有效的练习中, 我使用了regex.h中的几个正则表达式函数, 我的正则是这样的:

"^-?(0|[1-9]\\d*)(\\.\\d+)?([eE][+-]?\\d+)?$"

但是却带小数点的数字(-0.0,1.5)的测试都失败了, 不知道是什么原因...

第 7 篇 anwser 中 stringify_string() 的两个问题

  1. 如果参数 len 为 0 的话,lept_context_push(c, size = len * 6 + 2);就会发生可怕的事情了。
  2. 没有处理 UTF-8 (虽然算不上问题,我还是尝试解决了一下,写的不好,不过倒是很正确
static void json_stringify_string(json_context* c, const json_value* v)
{
    static const char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    size_t size;
    u_char* p;
    u_char* head;

    assert(v->json_s != NULL);
    if (v->json_len > 0)
        size = v->json_len * 6 - 2;
    else
        size = 2; /* "\"\"" */
    p = head = json_context_push(c, size);
    *p++ = '"';
    for (size_t i = 0; i < v->json_len; ++i) {
        u_char ch = (u_char) v->json_s[i];
        switch (ch) {
        case '\\': *p++ = '\\'; *p++ = '\\'; break;
        case '"':  *p++ = '\\'; *p++ = '"'; break;
        case '/':  *p++ = '\\'; *p++ = '/'; break;
        case '\t': *p++ = '\\'; *p++ = 't'; break;
        case '\b': *p++ = '\\'; *p++ = 'b'; break;
        case '\n': *p++ = '\\'; *p++ = 'n'; break;
        case '\r': *p++ = '\\'; *p++ = 'r'; break;
        case '\f': *p++ = '\\'; *p++ = 'f'; break;
        default:
            if (ch < 0x20) {
                *p++ = '\\'; *p++ = 'u'; *p++ = '0'; *p++ = '0';
                *p++ = hex_digits[ch >> 4];
                *p++ = hex_digits[ch & 15];
            } else if (ch > 0x7f) { /* Handle UTF-8. */
                unsigned u = json_decode_utf8((const u_char*) v->json_s, &i);;
                if (u <= 0xffff) {
                    *p++ = '\\'; *p++ = 'u';
                    *p++ = hex_digits[u >> 12];
                    *p++ = hex_digits[(u >> 8) & 15];
                    *p++ = hex_digits[(u >> 4) & 15];
                    *p++ = hex_digits[u & 15];
                } else if (u <= 0x10ffff) { /* Transfer codepoint to surrogate pair. */
                    unsigned h, l;
                    u -= 0x10000;
                    h = (u - (l = u % 0x400)) / 0x400;
                    h += 0xd800, l += 0xdc00;
                    *p++ = '\\'; *p++ = 'u';
                    *p++ = hex_digits[h >> 12];
                    *p++ = hex_digits[(h >> 8) & 15];
                    *p++ = hex_digits[(h >> 4) & 15];
                    *p++ = hex_digits[h & 15];
                    *p++ = '\\'; *p++ = 'u';
                    *p++ = hex_digits[l >> 12];
                    *p++ = hex_digits[(l >> 8) & 15];
                    *p++ = hex_digits[(l >> 4) & 15];
                    *p++ = hex_digits[l & 15];
                }
            } else {
                *p++ = v->json_s[i];
            }
            break;
        }
    }
    *p++ = '"';
    c->top -= size - (p - head);
}

从零开始的 JSON 库教程(一):启程解答篇 1. 修正 LEPT_PARSE_ROOT_NOT_SINGULAR

int lept_parse(lept_value* v, const char* json) {
    lept_context c;
    int ret;
    assert(v != NULL);
    c.json = json;
    v->type = LEPT_NULL;
    lept_parse_whitespace(&c);
    if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) {
        lept_parse_whitespace(&c);
        if (*c.json != '\0')
            ret = LEPT_PARSE_ROOT_NOT_SINGULAR;
    }
    return ret;
}

老师好,不知道是不是找到了一个小纰漏, :>
因为在之前规定了lept_parse() 若失败,会把 v 设为 null 类型,所以我觉得,应该在判断JSON文本没有完结之后,加一句 v->type =LEPT_NULL,这样在 test_parse_root_not_singular() 函数中,可以正确 解析"false x"; 这类的情况。否则 EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));将会打印错误信息。

关于 lept_member

lept_member 的 key
应不应该支持字符 ':'
比如
{
"name:1" : "LiHua"
}

对于解析TEST_STRING("\" \\ / \b \f \n \r \t", "\"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\"");的困惑

TEST_STRING("\" \\ / \b \f \n \r \t", "\"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\"");

TEST_STRING("\" \\ / \b \f \n \r \t", "\"\\\" \\\\ \/ \\b \\f \\n \\r \\t\"");

注意,下面的我把/前面的两个反斜线变成了一个,这样解析出的结果是一样的,也是正确的,但是这样不符合json对转义字符的定义啊,我觉得应该在对/这个字符要进行判定吧,判定其前面应该是\

tutorial07 test.c文件412行的测试例子

tutorial07 test.c文件412行的测试例子为

TEST_ROUNDTRIP("\"\\\" \\\\ / \\b \\f \\n \\r \\t\"");

缺少了转义,应该为

TEST_ROUNDTRIP("\"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\"");

然后我想问下,需不需要解析字符串类型的时候判断'/'这个字符,如果只出现'/'而前面是没有'//'应该是判定为LEPT_PARSE_INVALID_STRING_CHAR吧?

调用不存在函数

lept_get_number我在宏中错误的写成lept_get_num导致test函数检测不通过,但是编译器并没有提示函数未定义,返回的数据时大时小,请问这种调用不存在函数的时候,是怎么样的执行流程啊?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.