compiling c structs in c++ program

wegunterjr
Posts: 37
Joined: Thu Jun 07, 2018 3:05 am

compiling c structs in c++ program

Postby wegunterjr » Mon Mar 18, 2019 12:09 am

I am getting the following warning which results in a compile error:
sorry, unimplemented: non-trivial designated initializers not supported
I am trying to initialize a struct for doing an OTA..

Code: Select all

  esp_tls_cfg_t cfg = {
.cacert_pem_buf = (const unsigned char *)aws_root_ca_pem,
.cacert_pem_bytes = (unsigned int)(strlen(aws_root_ca_pem)+1),
         .non_block = true,
            .alpn_protos = "\x02h2",
};

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: compiling c structs in c++ program

Postby ESP_Angus » Mon Mar 18, 2019 1:04 am

C++ doesn't support C99-style named initializers for structs, and g++ (the C++ compiler we use) doesn't support any way to enable them as an optional extra.

You have three alternatives:
  • Order the elements in the named initializer in the same order they're declared in the struct. The C++ compiler should allow this.
  • Move code which initializes structs to a .c file, and call the .c file from your .cpp code.
  • Rewrite to individually initialize each element, something like:

    Code: Select all

    esp_tls_cfg_t cfg = { }; // note: brackets are important to zero-initialize the structure
    strlcpy(cfg.cacert_pem_buf, aws_root_ca_pem, sizeof(cfg.cacert_pem_buf));
    cfg.cacert_pem_bytes = strlen(aws_root_ca_pem)+1;
    cfg.non_block = true;
    
    static const char *proto = "h2";
    static const char *protos[] = { proto, NULL };
    cfg.alpn_protos = protos;
    
    (Compiler should optimize this to the same code as the C99 initializer, anyhow.)
Note: I changed the alpn_protos format here because I think this is actually the correct format, despite what the docs say. I'm going to check this with the ESP_TLS and HTTP/2 developers, but maybe what you had is actually correct in which case please change it back.

wegunterjr
Posts: 37
Joined: Thu Jun 07, 2018 3:05 am

Re: compiling c structs in c++ program

Postby wegunterjr » Mon Mar 18, 2019 4:05 am

Thanks for the help. I did try something similar as 3 and what you've shown there, but went ahead and tried what you suggested...
I am getting this error:

Code: Select all

error: invalid conversion from 'const unsigned char*' to 'char*' [-fpermissive]
for this line:

Code: Select all

	esp_tls_cfg_t cfg = { }; // note: brackets are important to zero-initialize the structure
	strlcpy(cfg.cacert_pem_buf, aws_root_ca_pem, sizeof(cfg.cacert_pem_buf));
and still getting the error about the bytes being read only...which is strange.

Code: Select all

error: assignment of read-only member 'esp_tls_cfg::cacert_pem_bytes'

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: compiling c structs in c++ program

Postby ESP_Angus » Mon Mar 18, 2019 4:50 am

Ah my mistake, this is a "const unsigned char *" not an array in the structure.
https://docs.espressif.com/projects/esp ... t_pem_bufE

Something like this should work:

Code: Select all

cfg.cacert_pem_buf = (const unsigned char *)aws_root_ca_pem;
(If there's any chance that aws_root_ca_pem pointer may become invalid during the life of the ESP_TLS config, you'll need to copy it into a static or other buffer first and then cacert_pem_buf to point to that buffer.)

wegunterjr
Posts: 37
Joined: Thu Jun 07, 2018 3:05 am

Re: compiling c structs in c++ program

Postby wegunterjr » Mon Mar 18, 2019 5:25 am

alright, tried that too...still getting the error about the bytes being read only... I am using 3.1.3 though, not 3.2 or the latest (would that be part of the problem...i tried digging into the core library, but couldn't find anything that said read only)..my struct has only 4 parts in the header...(none of them are read-only though)....
https://docs.espressif.com/projects/esp ... p_tls.html

Code: Select all

	esp_tls_cfg_t cfg = { }; // note: brackets are important to zero-initialize the structure

	cfg.cacert_pem_buf = (const unsigned char *)aws_root_ca_pem;
	cfg.cacert_pem_bytes = strlen(aws_root_ca_pem)+1;
	cfg.non_block = true;

	static const char *proto = "h2";
	static const char *protos[] = { proto, NULL };
	cfg.alpn_protos = protos;

Code: Select all

 error: assignment of read-only member 'esp_tls_cfg::cacert_pem_bytes'

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: compiling c structs in c++ program

Postby ESP_Angus » Mon Mar 18, 2019 5:33 am

Right, sorry, I think this is a bug - the field is incorrectly typed as const unsigned integer not an unsigned integer. Fixed in v3.2 and newer branches, not fixed in v3.1 branch yet.

I think your options here are:

1) Initialize all the fields in order to keep the compiler happy.
2) Edit esp_tls.h and change "const unsigned int cacert_pem_bytes;" to "unsigned int cacert_pem_bytes"
or
3) Initialize this one structure in C code and reference it from c++.

Sorry again. Fix coming ASAP.

EDIT: removed bad advice.

wegunterjr
Posts: 37
Joined: Thu Jun 07, 2018 3:05 am

Re: compiling c structs in c++ program

Postby wegunterjr » Mon Mar 18, 2019 5:43 am

woohoo..I am useful. HA!

okay..when you say at the top... do you mean at the top of my cpp file... like above main and all that?
or in the top of my ota_task before I set anything else up...

Cuz, i added this to the top of the file:

Code: Select all

esp_tls_cfg_t cfg = { .cacert_pem_bytes = strlen(aws_root_ca_pem) };
and added this in the ota_task where I am about to use it:

Code: Select all

cfg.cacert_pem_buf = (const unsigned char *)aws_root_ca_pem;
//	cfg.cacert_pem_bytes = strlen(aws_root_ca_pem)+1;
	cfg.non_block = true;

	static const char *proto = "h2";
	static const char *protos[] = { proto, NULL };
	cfg.alpn_protos = protos;
but i get the warnings that equal errors about non-trivial designated initializers....
src\main.cpp:261:67: sorry, unimplemented: non-trivial designated initializers not supported
esp_tls_cfg_t cfg = { .cacert_pem_bytes = strlen(aws_root_ca_pem) };
^
src\main.cpp:261:67: warning: missing initializer for member 'esp_tls_cfg::cacert_pem_buf' [-Wmissing-field-initializers]
src\main.cpp:261:67: warning: missing initializer for member 'esp_tls_cfg::cacert_pem_bytes' [-Wmissing-field-initializers]
src\main.cpp:261:67: warning: missing initializer for member 'esp_tls_cfg::non_block' [-Wmissing-field-initializers]

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: compiling c structs in c++ program

Postby ESP_Angus » Mon Mar 18, 2019 5:46 am

Sorry, I gave you bad advice (been a while since I wrote C++). Have edited previous post, just before you replied I think. :|

One bit of good news on the horizon, when we update to gcc 8 then "non-trivial designated initializer" support is added and the original code you wrote should work (maybe after some errors about the fields being out of order.)

wegunterjr
Posts: 37
Joined: Thu Jun 07, 2018 3:05 am

Re: compiling c structs in c++ program

Postby wegunterjr » Mon Mar 18, 2019 10:25 pm

Changing the esp_tls.h to use a unsinged int worked for me. Well, at least I can compile and it doesn't force reboot. HA!
ESP_Angus wrote:
Mon Mar 18, 2019 5:33 am
Right, sorry, I think this is a bug - the field is incorrectly typed as const unsigned integer not an unsigned integer. Fixed in v3.2 and newer branches, not fixed in v3.1 branch yet.

I think your options here are:

1) Initialize all the fields in order to keep the compiler happy.
2) Edit esp_tls.h and change "const unsigned int cacert_pem_bytes;" to "unsigned int cacert_pem_bytes"
or
3) Initialize this one structure in C code and reference it from c++.

Sorry again. Fix coming ASAP.

EDIT: removed bad advice.

Who is online

Users browsing this forum: MichaelS and 129 guests