Search code examples
c++esp32esp-idf

How to pass an std::vector<char>* as void* then cast the void* to std::vector<char>* back again?


I am using esp-idf to do some http requests, and I want to use c++ because I am more comfortable with it. The esp_http_client works more or less like this:

  1. You populate a designated initializer:
char[some_length] local_response_buffer;

// I want to use std::vector<char> local_response_buffer for dynamic allocation

esp_http_client_config_t config = {
        .host = "httpbin.org",
        .path = "/get",
        .disable_auto_redirect = true,
        .event_handler = http_event_handler,
        .user_data = local_response_buffer, // user_data is void* so the type is erased
    };

  1. While writing the event handler when data is received you get back the void* user_data and copy a temporary buffer of http data chunk into it:
esp_err_t http_event_handler(esp_http_client_event_t *evt)
{
    switch (evt->event_id) {
    /* handle other cases... */
    case HTTP_EVENT_ON_DATA:
        // append evt->data (which is actually C-style char* casted to void*) 
        // into evt->user_data (this is our user_data that has been casted to void*).
        // I want to use std::vector::insert here for this purpose.
        break;
}

I want to use std::vector instead of char[] for convenient dynamic allocation. What is the best way of doing this?


Solution

  • You already stated the answer in your question title. You can safely cast a std::vector* pointer to a void* pointer, and then cast it back to a std::vector* pointer.

    You can use the & operator to get the address of the vector, eg:

    vector<char> local_response_buffer;
    
    esp_http_client_config_t config = {
        ...
        .user_data = &local_response_buffer
    };
    
    ...
    
    esp_err_t http_event_handler(esp_http_client_event_t *evt)
    {
        ...
        vector<char> *buffer = static_cast<vector<char>*>(evt->user_data);
        char *data = static_cast<char*>(evt->data);
        buffer->insert(buffer->end(), data, data + evt->data_len);
        ...
    }
    

    Alternatively, you might consider using std::string instead of std::vector, eg:

    string local_response_buffer;
    
    esp_http_client_config_t config = {
        ...
        .user_data = &local_response_buffer
    };
    
    ...
    
    esp_err_t http_event_handler(esp_http_client_event_t *evt)
    {
        ...
        string *buffer = static_cast<string*>(evt->user_data);
        buffer->append(static_cast<char*>(evt->data), evt->data_len);
        ...
    }