현대 C++ 애플리케이션 개발에서는 데이터를 외부 시스템과 주고받는 일이 빈번하게 발생하며, 이 과정에서 직렬화(serialization)와 역직렬화(deserialization)가 핵심적인 역할을 합니다. 특히 JSON은 그 가벼움과 인간 친화적인 형식 덕분에 네트워크 통신 및 설정 파일 등 다양한 분야에서 표준처럼 사용되고 있습니다. 본 문서에서는 C++ 구조체(struct)와 JSON 데이터를 매끄럽게 변환하는 방법을 nlohmann/json 라이브러리를 중심으로 설명합니다.
nlohmann/json 라이브러리 개요
nlohmann/json은 C++11 이상을 지원하는 헤더 전용(header-only) JSON 라이브러리로, 복잡한 의존성 없이 단일 헤더 파일만 포함하면 바로 사용 가능합니다. 객체 지향적이고 직관적인 API를 제공하여 C++ 데이터를 JSON으로, 또는 그 반대로 변환하는 작업을 매우 간소화합니다.
라이브러리 설치 방법
프로젝트에 이 라이브러리를 추가하는 방법은 다음과 같습니다.
- 패키지 매니저 사용 (예: vcpkg)
vcpkg install nlohmann-json
- 수동 설치: GitHub 저장소에서
json.hpp파일을 다운로드하고 프로젝트 경로에 배치한 후 포함합니다.
#include "json.hpp"
기본 구조체와 JSON 변환
간단한 예제로 사람 정보를 담는 User 구조체를 정의해 보겠습니다.
struct User {
std::string name;
int id;
std::string email;
};
이 구조체를 JSON과 상호 변환하기 위해선 특수한 ADL(Argument-Dependent Lookup) 기반 함수인 to_json과 from_json을 오버로드해야 합니다.
#include <iostream>
#include <string>
#include "json.hpp"
using json = nlohmann::json;
struct User {
std::string name;
int id;
std::string email;
};
// 직렬화: User → JSON
void to_json(json& j, const User& u) {
j = json{
{"name", u.name},
{"id", u.id},
{"email", u.email}
};
}
// 역직렬화: JSON → User
void from_json(const json& j, User& u) {
u.name = j.value("name", "");
u.id = j.value("id", 0);
u.email = j.value("email", "");
}
j.value() 메서드는 존재하지 않는 키에 대해 기본값을 반환하므로 at()보다 안전하게 사용할 수 있습니다.
사용 예시
다음 코드는 위에서 정의한 변환 함수를 활용하는 예입니다.
int main() {
// 객체 생성
User user{"Kim Minsoo", 1001, "kim@example.com"};
// JSON으로 변환
json j = user;
std::cout << "JSON 출력: " << j.dump(2) << std::endl;
// 다시 객체로 복원
User restored = j.get<User>();
std::cout << "복원된 이름: " << restored.name << ", ID: " << restored.id << std::endl;
return 0;
}
중첩된 구조체 처리
구조체 내부에 또 다른 구조체가 포함된 경우에도 동일한 패턴을 재귀적으로 적용할 수 있습니다.
struct Location {
std::string city;
std::string zipcode;
};
struct Employee {
std::string name;
int age;
Location location;
};
// 중첩 타입 변환 함수
void to_json(json& j, const Location& loc) {
j = json{{"city", loc.city}, {"zipcode", loc.zipcode}};
}
void to_json(json& j, const Employee& emp) {
j = json{
{"name", emp.name},
{"age", emp.age},
{"location", emp.location}
};
}
void from_json(const json& j, Location& loc) {
loc.city = j.value("city", "Unknown");
loc.zipcode = j.value("zipcode", "");
}
void from_json(const json& j, Employee& emp) {
emp.name = j.value("name", "");
emp.age = j.value("age", 0);
emp.location = j.value("location", Location{});
}
중첩된 필드도 자연스럽게 변환되며, get_to()나 value()를 통해 안전하게 값을 추출할 수 있습니다.
마무리
nlohmann/json 라이브러리는 C++에서 JSON 처리를 매우 직관적이고 유연하게 만들어 줍니다. 구조체에 대한 직렬화/역직렬화 함수를 작성함으로써, 복잡한 데이터도 깔끔하게 JSON과 상호 운용할 수 있습니다. 헤더 전용이라는 장점까지 더해져 소규모 프로젝트부터 대규모 시스템까지 폭넓게 활용 가능합니다.