bblanchon / ArduinoJson

📟 JSON library for Arduino and embedded C++. Simple and efficient.
https://arduinojson.org
MIT License
6.7k stars 1.12k forks source link

Unable to use a DynamicJsonDocument within a struct #1998

Closed FerGT50 closed 10 months ago

FerGT50 commented 10 months ago

Description When defining a struct which has a DynamicJsonDocument as member, I get a compiler error:

error: expected identifier before numeric constant DynamicJsonDocument testJDoc(4096);

Troubleshooter's report

  1. The program uses ArduinoJson 6
  2. The issue happens at compile time
  3. Error says "expected identifier before string constant"
  4. Program doesn't target a WisBlock RUI3

Environment

Reproduction code

#include <ArduinoJson.h>

// Typedefs
typedef struct JSONtestStruct
{ 
  DynamicJsonDocument testJDoc(4096);  
  int someInt;
} JSONtestStruct;

typedef JSONtestStruct* JSONtestType;

// Globals
JSONtestType myJSON;

// Setup
void setup() 
{
  myJSON = (JSONtestType) malloc(sizeof(JSONtestStruct));

  myJSON->testJDoc["testvalue"] = 42;
  myJSON->someInt = 42;
}

// Loop
void loop() {

}

Remarks Compiler error:

jsontest1:6:32: error: expected identifier before numeric constant DynamicJsonDocument testJDoc(4096); ^~~~ jsontest1:6:32: error: expected ',' or '...' before numeric constant C:\Users\Fernando\Documents\Arduino\jsontest1\jsontest1.ino: In function 'void setup()': jsontest1:20:31: error: invalid types '[const char [10]]' for array subscript myJSON->testJDoc["testvalue"] = 42; ^

bblanchon commented 10 months ago

Hi @FerGT50,

Thank you for reporting this issue.

Indeed, you cannot call a constructor from the member's declaration. Instead, you must call the member's constructor from the class constructor.

struct JSONtestStruct
{ 
  DynamicJsonDocument testJDoc;  
  int someInt;

  JSONtestStruct() : testJDoc(4096) {}
};

See Constructors and member initializer lists

Best regards, Benoit

FerGT50 commented 10 months ago

Hello, thanks for replying. If possible, could your post a complete example, please? Just replacing my JSONtestStruct with yours leads to compiler errors.

Slightly different topic: I tried to switch to StaticJSONDocument, hoping to avoid the constructor issue. Unfortunately, this sketch:


#include <ArduinoJson.h>

#define JSON_SIZE 256

// Typedefs
typedef struct JSONtestStruct
{ 
  StaticJsonDocument <JSON_SIZE>JDoc;
  int someInt;
} JSONtestStruct;

typedef JSONtestStruct* JSONtestType;

// Globals
JSONtestType g_myJSON = NULL;
char* g_buffer = NULL;

void structInit()
{
  g_myJSON = (JSONtestType) malloc(sizeof(JSONtestStruct));
  if (g_myJSON == NULL)
  {
    Serial.printf("\nMalloc failed!\n");
  }
}

// Setup
void setup() 
{
  structInit();

  g_buffer = (char*) malloc(2 * JSON_SIZE);

  g_myJSON->JDoc["testvalue"] = 42;
  g_myJSON->someInt = 42;

  Serial.begin(115200);
}

// Loop
void loop() 
{
  int value = 0;
  int jsonLen = 0;

  delay(5000);

  jsonLen = serializeJson(g_myJSON->JDoc, g_buffer, 2*JSON_SIZE);
  Serial.printf("JSON (len=%d):\n%s\n", jsonLen, g_buffer);

  // Update
  g_myJSON->JDoc["testvalue"] = value;
  g_myJSON->someInt = value;
  value++;
}

throws the ESP32 into a bootloop crash when executing g_myJSON->JDoc["testvalue"] = 42;

so I guess I did not really grasp StaticJsonDocument either...!

Thanks for your support

bblanchon commented 10 months ago

Hi @FerGT50,

In C++, if you want to allocate an object on the heap, you must call new, not malloc(). In addition to allocating the memory block, new calls the constructor of the class, so the object is correctly initialized. You can find an express C++ course in the second chapter of my book Mastering ArduinoJson.

Best regards, Benoit

FerGT50 commented 10 months ago

In the end I dropped the struct approach and switched to a class, with a StaticJsonDocument as member; now everything works as expected.