cJSON Library

sesame·2023년 10월 30일
0

규격

목록 보기
8/8

참고
http://www.json.org/
https://github.com/DaveGamble/cJSON#parsing-json

cJSON 프로젝트 통합 방법

1. 소스 복사하기

전체 라이브러리 : cJson.h, cJson.c

cJSON은 ANSI C(C89)로 작성되었음

2. CMake // TODO

가장 많은 기능을 얻을 수 있음
2.8.5 버전 이상의 CMake에서 지원됨

mkdir build
cd build
cmake ..

-> Makefile 및 기타 여러 파일 생성됨
그다음 컴파일

3. Makefile

이 방법은 더 이상 사용되지 않음
CMake 사용

Make all
or
Make install

4. Meson(중간자)

libcjson 종속성을 포함해야함

project('c-json-example', 'c')
cjson = dependency('libcjson')
example = executable(
'example',
'example.c',
dependencies: [cjson],
)

5. Vcpkg

cJSON 다운로드 및 설치 가능

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install cjson

Including cJSON

#include <cjson/cJSON.h>


Data Structure

/* The cJSON structure: */
typedef struct cJSON
{
    struct cJSON *next;
    struct cJSON *prev;
    struct cJSON *child;
    int type;
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    int valueint;
    double valuedouble;
    char *string;
} cJSON;

1. JSON type

1) cJSON_Invalid

값이 포함되지 않은 잘못된 항목

  • CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);

2) cJSON_False

false boolean

  • CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
  • CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);

3) cJSON_True

true boolean

  • CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
  • CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);

4) cJSON_NULL

NULL

  • CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);

5) cJSON_Number

숫자 값
double인 경우 valuedouble로 저장되며 valueint에도 저장됨
숫자가 정수 범위 벗어나는 경우 valueint에 INT_MAX 또는 INT_MIN 사용

  • CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);

6) cJSON_String

문자열 값
valuestring에 널로 끝나도록 저장됨

  • CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);

7) cJSON_Array

배열 값
배열의 값을 나타내는 cJSON 항목의 링크된 목록을 자식으로 가리킴으로써 구현됨
next, prev 사용하여 함께 연결
첫번째 요소: prev.next==NULL
마지막 요소: next==NULL

  • CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);

8) cJSON_Object

개체 값
객체는 배열과 동일한 방식으로 저장됨
차이점: 객체의 item이 해당 key를 string에 저장

  • CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);

9) cJSON_Raw

valuestring 널 종단 문자로 저장되는 모든 종류의 JSON을 나타냄
ex) 성능을 절약하기 위해 동일한 정적 JSON이 계속해서 인쇄되지 않도록 사용할 수 있음

  • CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);

2. flags

1) cJSON_IsReference // TODO

#define cJSON_IsReference 256

child가 가리키는 항목이 valuestring을 소유하지않고 참조일 뿐이므로 cJSON_Delete 및 다른 함수는 child/valuestring가 아닌 항목만 할당 해제함
value

2) cJSON_StringIsConst

#define cJSON_StringIsConst 512

string constant 문자열을 가리킴
cJSON_Delete와 다른 함수들이 이 string의 할당을 해제할 수 없음을 나타냄


Working with the data structure

cJSON_Create...() 함수로 할당
cJSON_Delete...()함수로 할당 해제

📌중요
array/object 항목을 이미 추가한 경우 cJSON_Delete로 삭제해서는 안됨
array/object에 추가하면 소유권 이전되므로 해당 array/object가 삭제될 때 삭제됨
cJSON_ValueString 사용하여 cJSON_String의 값 문자열을 변경 가능하고 이전 값 문자열을 수동으로 해제할 필요가 없음


1. Basic Type

1) NULL

  • cJSON_CreateNULL()

2) Booleans

  • cJSON_CreateTrue()
  • cJSON_CreateFalse()
  • cJSON_CreateBool()

3) numbers

  • cJSON_CreateNumber()
    valuedouble, valueint 모두 설정됨
    정수 범위 벗어나면 INT_MAX or INT_MIN

4) strings

  • cJSON_CreateString() : 문자열 복사
  • cJSON_CreateStringReference() : 문자열 직접 가리킴, valuestring이 생명주기동안 cJSON_Delete()로 삭제되지 않음(constant)

2. Array Type

  • cJSON_CreateArray() : 빈 배열 할당
  • cJSON_CreateArrayReference() : 해당 내용을 소유하지 않는 배열 할당, cJSON_Delete에 의해 삭제되지 않음

1) 배열에 item 추가 시

  • cJSON_AddItemToArray() : item의 끝에 추가
  • cJSON_AddItemReferenceToArray() : 다른 item, array 또는 valuestring에 대한 참조로 추가됨
  • cJSON_InsertItemInArray() : 중간에 item 추가, 주어진 0 기준 인덱스에 item 삽입 후 기존 항목 모두 오른쪽으로 이동

2) 배열에 항목 분리하여 사용 시

  • cJSON_DetachItemFromArray() : 주어진 인덱스에서 항목을 꺼내 계속 사용, 함수 사용하면 분리된 item이 반환되므로 포인터에 할당해야함(그렇지 않으면 메모리릭 발생)

3) 배열에 item 삭제 시

  • cJSON_DeleteItemFromArray() : cJSON_Delete를 통해 분리된 item을 삭제

4) 배열에 item 변경(교체) 시

  • cJSON_ReplaceItemInArray() : 인덱스로 변경
  • cJSON_ReplaceItemViaPointer() : element에 대한 포인터로 변경, 실패 시 0 반환
    내부 로직: 이전 item 분리 후 삭제, 새 item 그 자리에 삽입

5) etc

  • cJSON_GetArraySize() : 배열의 크기 get
  • cJSON_GetArrayItem() : 인덱스로 배열의 element get

array가 linkedlist 처럼 저장되므로 인덱스를 통해 반복하는 것은 비효율적
cJSON_ArrayForEach() 매크로를 사용하여 배열을 반복할 수 있음
// TODO

3. Object Type

cJSON_CreateObject() : 빈 개체 할당
cJSON_CreateObjectReference() : content를 소유하지 않는 개체 할당

1) 개체에 item 추가

  • cJSON_AddItemToObject() : 개체에 item 추가
  • cJSON_AddItemToObjectCS() : constant(상수) 또는 참조(item의 key, CJSON struct의 string) item 추가
  • cJSON_AddItemReferenceToArray() 사용하면 다른 object, array, string에 대한 참조로 추가할 수 있음

2) object에서 item 꺼낼 때

  • cJSON_DetachItemFromObjectCaseSensitive() : 분리된 항목이 반환되므로 포인터에 할당, or 메모리릭

3) object에서 item 삭제

  • cJSON_DeleteItemFromObjectCaseSensitive() : ==cJSON_Delete()

4) object에서 item 변경

  • cJSON_ReplaceItemInObjectCaseSensitive() : key 사용하여 변경
  • cJSON_ReplaceItemViaPointer() : element의 포인터 지정하여 변경, 실패 시 0 반환
    내부 로직 : 이전 항목 분리한 후 삭제, 새 항목 그 자리에 삽입

5) etc

  • cJSON_GetArraySize() : object의 크기 가져옴, object가 array 처럼 저장되기 때문에 사용 가능
  • cJSON_GetObjectItemCaseSensitive() : object 내부의 item에 접근하는 함수
  • cJSON_ArrayForEach() : iterate over(반복)
  • cJSON_AddNullToObject() : object에 새로운 item 빠르게 생성하여 추가, 실패시 새 item 포인터, NULL 반환

Parsing Json

널 종단 문자열로 끝나는 JSON Parsing 하는 경우

cJSON *json = cJSON_Parse(string);

널 종단 문자열로 끝나는지 확실하지 않은 JSON Parsing 하는 경우

cJSON *json = cJSON_ParseWithLength(string, buffer_length);

cJSON_Parse()는 malloc()와 free()를 기본적으로 사용
그러나, JSON_InitHooks()로 변경될 수 있음

오류 발생하는 경우
cJSON_GetErrorPtr() : 입력 문자열의 오류 위치에 대한 포인터에 접근 가능

멀티 쓰레드 환경에서 race condition 발생
멀티 쓰레드 환경에서는 cJSON_ParseWithOpts()와 return_parse_end를 함께 사용하는 것이 좋음

더 많은 옵션을 원하는 경우
cJSON_ParseWithOpts( const char *value, const char **return_parse_end, cJSON_bool require_null_terminated
)
return_parse_end는 입력 문자열의 JSON 끝 또는 오류가 발생한 위치의 포인터 반환(따라서 cJSON_GetErrorPtr()을 스레드 세이프 방식으로 대체)
require_null_terminated는 1로 설정 시 입력 문자열에 JSON 다음의 데이터가 포함되어있으면 오류가 됨

버퍼 길이를 지정하는 더 많은 옵션을 원하는 경우
cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)

Printing Json

char *string = cJSON_Print(json);

string에 JSON 표현을 할당함
할당했기 때문에 할당 해제 해야함(free 쓰지만, cJSON_InitHooks()로 설정된 것에 따라 달라짐)

  • cJSON_Print() : whitespace를 사용하여 포맷으로 출력
    첫 버퍼 사이즈 = 256byte
  • cJSON_PrintUnformatted() : 포맷없이 출력
  • cJSON_PrintBuffered( const cJSON *item, int prebuffer, cJSON_bool fmt ) : 버퍼 크기 임의 지정 출력
    fmt = whitespace on/off
    prebuffer = 출력하기 위한 첫 버퍼 사이즈
  • cJSON_PrintPreallocated( cJSON item, char buffer, const int length, const cJSON_bool format ) : 동적 버퍼 할당 방지하여 출력
    buffer의 크기보다 큰 경우 다음 버퍼 할당하지 않고 실패 반환
    return 성공 1, 실패 0

첫 버퍼 사이즈 넘는 경우
새로운 버퍼를 할당하여 다음 버퍼 출력 전 계속 복사되어있음

Examples

주의사항

1. Zero Character

cJSON은 '\0' or \u0000 문자를 지원하지 않는다

2. Character Encoding

UTF-8 인코딩된 입력만 지원

3. C standard

cJSON은 ANSI C(or C89, C90)으로 작성됨
컴파일러나 C 라이브러리가 이 표준을 따르지 않으면 올바른 동작이 보장되지 않음

4. Floating Point Numbers

cJSON이 지원하는 부동 소수점 literal의 최대 길이는 현재 63자

5. Deep Nesting Of Arrays And Objects

cJSON은 stack overflow 발생할 수 있기 때문에 너무 중첩된 array, object를 지원하지 않음
방지하기 위해 CJSON_NESTING_LIMIT 사용
(default로 1000이고 컴파일 시 변경 가능)

6. Thread Safety

  • cJSON_GetErrorPtr() -> cJSON_ParseWithOpts()의 return_parse_end parameter
  • cJSON_InitHooks() : 스레드에서 cJSON을 사용하기 전에만 호출됨
  • setlocale : cJSON 함수에 대한 모든 호출이 반환되기 전에는 호출되지 않음

7. Case Sensitivity

cJSON 처음 만들어졌을 때 JSON 표준 따르지 않고 대문자 소문자 구분하지 않았음
정확하고 표준을 준수하는 동작 원하면 CaseSensitive 함수 사용해야함

8. Duplicate Object Members

cJSON은 중복된 이름의 멤버를 포함하는 object parsing, print 지원

  • cJSON_GetObjectItemCaseSensitive() : 항상 첫번째 개체만 반환함

0개의 댓글