2012-05-08 2 views
0

Позвольте мне начать с того, что я не эксперт в C. Я просматривал код анализатора JSON.JSON Parser in C (Prints 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?

Любое понимание этого было бы действительно полезно.

ответ

1

Что он делает, это превратить управляющие символы в escape-последовательности, которые вы обычно используете в исходном коде 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“на выходе.

  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.

+0

Очень хорошо объяснил, на время, которое потребовалось! –

1

Что этот код делает замену непечатаемые символы, такие как U + 000A (питающей линии) с помощью управляющих последовательностей в строке, такие как \n (два символа, \\ и 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++; 
+0

Блестяще спасибо большое –

1

Функции побег содержимого строки, не украшающий его - например, он преобразует символ возврата каретки (ASCII-код 13) в строку \r, он преобразует другие непечатаемые символы в их код ect.

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

места в ptr2 шестнадцатеричное представление token (x), дополненное 0 с быть четыре символа в длине (в 04), и с префиксом u - следующий

ptr2+=5; 

движется указатель ptr2 прямо после строки, только что сгенерированной sprintf - длиной 5 символов.