Free & open source — no account required

v1.2.5-PRICING-19
Web & Frontend • Engineering Documentation

JSON to C Struct Generator

This technical guide provides an in-depth analysis of the json to c struct engine, best practices for implementation, and data security standards.

JSON to C Struct: Generating typedef struct with cJSON

When integrating a JSON API into a C project — whether for an embedded system, a Linux daemon, or a game engine — the first step is defining a typedef struct that mirrors the JSON schema. C has no reflection and no runtime type system, so every field mapping must be written by hand unless you generate it. TypeMorph reads your JSON sample, infers C types, and outputs a complete typedef struct along with a cJSON parse function. Everything runs in your browser — your data never leaves your machine.

Live Example: API Response to C Struct

// Input JSON
{
  "device_id": "sensor_042",
  "temperature": 23.7,
  "humidity": 61,
  "is_active": true,
  "firmware": "2.1.4",
  "error_code": null
}

// Generated C (C99, cJSON)
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "cJSON.h"

typedef struct {
  char *device_id;
  double temperature;
  int32_t humidity;
  bool is_active;
  char *firmware;
  char *error_code;  /* nullable */
} Root;

Root root_from_json(const char *json_str) {
  Root result = {0};
  cJSON *root = cJSON_Parse(json_str);
  if (!root) return result;

  cJSON *_device_id = cJSON_GetObjectItemCaseSensitive(root, "device_id");
  if (cJSON_IsString(_device_id)) result.device_id = _device_id->valuestring;

  cJSON *_temperature = cJSON_GetObjectItemCaseSensitive(root, "temperature");
  if (cJSON_IsNumber(_temperature)) result.temperature = _temperature->valuedouble;

  cJSON *_humidity = cJSON_GetObjectItemCaseSensitive(root, "humidity");
  if (cJSON_IsNumber(_humidity)) result.humidity = (int32_t)_humidity->valuedouble;

  cJSON *_is_active = cJSON_GetObjectItemCaseSensitive(root, "is_active");
  if (cJSON_IsBool(_is_active)) result.is_active = cJSON_IsTrue(_is_active);

  cJSON *_firmware = cJSON_GetObjectItemCaseSensitive(root, "firmware");
  if (cJSON_IsString(_firmware)) result.firmware = _firmware->valuestring;

  cJSON_Delete(root);
  return result;
}

C Type Mapping from JSON

JSON's type system maps to C types as follows. The key difference from higher-level languages: C strings are pointers (char *) or fixed-size arrays, not value types — and you must manage their lifetime explicitly.

// JSON → C type mapping
// "string"  → char *            (points into cJSON tree; copy with strdup() for ownership)
// number    → double            (safe default; cast to int32_t if always whole)
// integer   → int32_t           (use int64_t for large IDs, uint32_t for sizes)
// boolean   → bool              (requires #include <stdbool.h>, C99+)
// null      → char * = NULL     (pointer null represents JSON null naturally)
// object    → nested typedef struct
// array     → T *items + int items_count

// String ownership — the common pattern:
typedef struct {
  char *name;       // borrowed: points into cJSON tree (freed with cJSON_Delete)
} BorrowedUser;

typedef struct {
  char *name;       // owned: allocated with strdup(), must be free()'d
} OwnedUser;

void parse_owned(const char *json_str, OwnedUser *out) {
  cJSON *j = cJSON_Parse(json_str);
  cJSON *name = cJSON_GetObjectItemCaseSensitive(j, "name");
  if (cJSON_IsString(name)) {
    out->name = strdup(name->valuestring); // take ownership
  }
  cJSON_Delete(j); // safe to delete — we own a copy
}

Nested Structs

// Input JSON
{
  "user_id": "usr_001",
  "name": "Ada Lovelace",
  "address": {
    "street": "123 Babbage Ln",
    "city": "London",
    "zip": "EC1A 1BB"
  }
}

// Generated C — nested structs defined first
typedef struct {
  char *street;
  char *city;
  char *zip;
} RootAddress;

typedef struct {
  char *user_id;
  char *name;
  RootAddress address;
} Root;

Root root_from_json(const char *json_str) {
  Root result = {0};
  cJSON *j = cJSON_Parse(json_str);
  if (!j) return result;

  cJSON *_user_id = cJSON_GetObjectItemCaseSensitive(j, "user_id");
  if (cJSON_IsString(_user_id)) result.user_id = _user_id->valuestring;

  cJSON *_name = cJSON_GetObjectItemCaseSensitive(j, "name");
  if (cJSON_IsString(_name)) result.name = _name->valuestring;

  cJSON *_address = cJSON_GetObjectItemCaseSensitive(j, "address");
  if (cJSON_IsObject(_address)) {
    cJSON *_street = cJSON_GetObjectItemCaseSensitive(_address, "street");
    if (cJSON_IsString(_street)) result.address.street = _street->valuestring;
    cJSON *_city = cJSON_GetObjectItemCaseSensitive(_address, "city");
    if (cJSON_IsString(_city)) result.address.city = _city->valuestring;
    cJSON *_zip = cJSON_GetObjectItemCaseSensitive(_address, "zip");
    if (cJSON_IsString(_zip)) result.address.zip = _zip->valuestring;
  }

  cJSON_Delete(j);
  return result;
}

Arrays: Pointer + Count Pattern

// Input JSON
{
  "name": "Server Rack A",
  "sensor_ids": ["s001", "s002", "s003"],
  "temperatures": [21.3, 22.1, 20.8]
}

// Generated C — array fields become pointer + count pairs
typedef struct {
  char *name;
  char **sensor_ids;
  int sensor_ids_count;
  double *temperatures;
  int temperatures_count;
} Rack;

Rack rack_from_json(const char *json_str) {
  Rack r = {0};
  cJSON *j = cJSON_Parse(json_str);
  if (!j) return r;

  cJSON *_name = cJSON_GetObjectItemCaseSensitive(j, "name");
  if (cJSON_IsString(_name)) r.name = _name->valuestring;

  cJSON *_ids = cJSON_GetObjectItemCaseSensitive(j, "sensor_ids");
  if (cJSON_IsArray(_ids)) {
    r.sensor_ids_count = cJSON_GetArraySize(_ids);
    r.sensor_ids = malloc(r.sensor_ids_count * sizeof(char *));
    int i = 0;
    cJSON *item;
    cJSON_ArrayForEach(item, _ids) {
      if (cJSON_IsString(item)) r.sensor_ids[i++] = item->valuestring;
    }
  }

  cJSON *_temps = cJSON_GetObjectItemCaseSensitive(j, "temperatures");
  if (cJSON_IsArray(_temps)) {
    r.temperatures_count = cJSON_GetArraySize(_temps);
    r.temperatures = malloc(r.temperatures_count * sizeof(double));
    int i = 0;
    cJSON *item;
    cJSON_ArrayForEach(item, _temps) {
      if (cJSON_IsNumber(item)) r.temperatures[i++] = item->valuedouble;
    }
  }

  // NOTE: Don't cJSON_Delete(j) here — strings point into the cJSON tree.
  // Either copy them with strdup(), or keep cJSON alive until done with r.
  return r;
}

Frequently Asked Questions

When should I use C instead of C++? Use C when targeting embedded systems (bare-metal, RTOS), writing kernel modules or drivers, or working in environments where C++ runtime overhead is unacceptable. C is also the right choice when interfacing with other languages via FFI — nearly every language can call a C ABI. If you have a choice and the environment supports it, C++ gives you std::string and RAII which eliminate many of the memory management pitfalls.

What is cJSON and why use it? cJSON is a single-file, MIT-licensed JSON parser for C. It's the most widely used C JSON library, found in ESP-IDF (ESP32), Zephyr RTOS, and countless embedded projects. Add it to your project by copying cJSON.c and cJSON.h — no build system changes required. Alternatives include jansson (owned strings, higher-level API) and jsmn (zero-allocation, token-based).

Why does the generated code use char * instead of char name[256]? Pointer strings are more flexible for API responses where string lengths vary. Fixed-size arrays (char name[64]) are better for embedded targets where malloc is unavailable or undesirable. For embedded use, change char * fields to char field[MAX_LEN] and use strncpy instead of direct pointer assignment.

Is my JSON sent to a server? No. TypeMorph runs entirely in your browser — none of your data leaves your machine.

Developer FAQ

Is the processing local-only?

Absolutely. TypeMorph operates entirely within your browser's sandbox. We use Web Workers for high-performance computation without ever transmitting your JSON, SQL, or API data to a remote server.

Can I use this for enterprise projects?

Yes. The tool is designed for professional software engineers who require GDPR compliance and data privacy. It is trusted by developers at top-tier startups and financial institutions.