0

首先让我说我不是 C 方面的专家。我一直在审查 JSON 解析器的代码。

我试图理解这段代码。

/* Render the cstring provided to an escaped version that can be printed. */
static char *print_string_ptr(const char *str)
{
    const char *ptr;
    char *ptr2,*out;
    int len=0;
    unsigned char token;

    if (!str)
        return cJSON_strdup("");
    ptr = str;
    while ((token = *ptr) && ++len) {
        if (strchr("\"\\\b\f\n\r\t", token))
            len++;
        else if (token < 32)
            len += 5;
        ptr++;
    }

    out = (char*)cJSON_malloc(len + 3);
    if (!out)
      return 0;

    ptr2 = out;
    ptr = str;
    *ptr2++ = '\"';
    while (*ptr) {
        if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\')
            *ptr2++ = *ptr++;
        else {
            *ptr2++ = '\\';
            switch (token = *ptr++) {
                case '\\':      *ptr2++='\\';   break;
                case '\"':      *ptr2++='\"';   break;
                case '\b':      *ptr2++='b';    break;
                case '\f':      *ptr2++='f';    break;
                case '\n':      *ptr2++='n';    break;
                case '\r':      *ptr2++='r';    break;
                case '\t':      *ptr2++='t';    break;
                default:
                    /* escape and print */
                    sprintf(ptr2, "u%04x", token);
                    ptr2 += 5;
                    break;
            }
        }
    }
    *ptr2++ = '\"';
    *ptr2++ = 0;
    return out;
}

对这段代码的实际工作方式进行一个非常概括的总结会非常棒,我的印象是它“美化”了 JSON 字符串,对吗?

乍一看,它似乎是用 r 代替 \r,但这样做有什么意义呢?

我一直在研究 sprintf 的功能,但只是针对简单的事情,例如打印货币值或其他格式问题。但我不知道 sprintf 函数在这里做什么:

sprintf(ptr2,"u%04x",token);ptr2+=5;

ptr2+=5 的目的是什么?

对此的任何见解都会非常有帮助。

4

3 回答 3

1

\n这段代码所做的是用字符串中的转义序列(例如(两个字符\\和))替换不可打印的字符,例如 U+000A(换行符n)。

变量ptr2指向输出中的当前点,变量ptr指向正在写入输出的字符串中的当前点。

// Write "u" followed by a 4-digit hexadecimal number to the output
sprintf(ptr2,"u%04x",token);
// Advance the output pointer by five spaces
ptr2 += 5; 

通过对比,

*ptr2++ = 'r';

是相同的,

// Write "r" to the output
*ptr = 'r';
// Advance the output pointer one space
ptr++;
于 2012-05-08T21:11:48.900 回答
1

该函数正在转义字符串内容,而不是美化它 - 例如,它将回车符(ASCII 代码 13)转换为字符串\r,它在其代码等中转换其他不可打印的字符。

sprintf(ptr2,"u%04x",token);

放入(the )ptr2的十六进制表示,用 s 填充为长度为四个字符 (the ),并以- 为前缀tokenx004u

ptr2+=5;

ptr2指针移到刚刚由sprintf- 生成的字符串之后,即 5 个字符长。

于 2012-05-08T21:14:51.163 回答
1

它所做的是将控制字符转换为您通常在 C 源代码中使用的转义序列。

if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') 
    *ptr2++=*ptr++;

这基本上是在说“如果我们有一个普通字符,如字母、数字等,只需将其直接从输入复制到输出。”

 else
 {
     *ptr2++='\\';

否则,我们将在输出中生成一个以反斜杠开头的转义序列。

     switch (token=*ptr++)
     {
         case '\\':      *ptr2++='\\';   break;
         case '\"':      *ptr2++='\"';   break;
         case '\b':      *ptr2++='b';    break;

然后,根据它找到的控制字符,它生成转义序列的第二个字符,因此输入中的实际“退格”字符(比较等于“\b”)将产生两个字符“\”和'b' 在输出中。

          case '\f':      *ptr2++='f';    break;
          case '\n':      *ptr2++='n';    break;
          case '\r':      *ptr2++='r';    break;
          case '\t':      *ptr2++='t';    break;

换页、换行、回车和制表符也是如此。

          default: sprintf(ptr2,"u%04x",token);ptr2+=5;   break;  

否则,将控制字符渲染为十六进制,所以它变成类似\1234.

于 2012-05-08T21:16:59.803 回答