I’m currently doing c++ with OpenCL, where a c-style struct is required to carry configuration information from the c++ host to the OpenCL kernel. Given that dynamically allocated arrays are not guaranteed to be supported by every OpenCL implementation, I must ensure every array accessible by the kernel code be static-sized. However, I run into weird errors when initializing static arrays within a c-style struct.
The error could be reproduced by the following PoC:
#include <cstring>
#include <string>
#define ID_SIZE 16
struct conf_t {
const unsigned int a;
const unsigned int b;
const unsigned char id[ID_SIZE];
};
int main() {
const std::string raw_id("0123456789ABCDEF");
unsigned char id[ID_SIZE];
memcpy(id,raw_id.c_str(),ID_SIZE);
struct conf_t conf = {10,2048,id};
}
And the following error:
poc.cc: In function ‘int main()’:
poc.cc:15:39: error: array must be initialized with a brace-enclosed initializer
15 | struct conf_t conf = {10,2048,id};
| ^~
It’s true that I could remove the const keyword in the struct and get rid of the stack variable id, where &(conf.id) could be the first parameter of memcpy. However, I’d like to keep the immutability of fields in the conf struct, which enables the compilers to check undesired modifications.
For my understanding, structs in c should have the following memory layout:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ id +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Given the stack variable id is also with static size, I’m confused why the c++ compiler still looks for a brace-enclosed initializer even if id is already a static-sized array.
>Solution :
The error on the initialization:
#include <cstring>
#include <string>
#define ID_SIZE 16
struct conf_t {
const unsigned int a;
const unsigned int b;
const unsigned char id[ID_SIZE];
};
int main() {
const std::string raw_id("0123456789ABCDEF");
unsigned char id[ID_SIZE];
memcpy(id, raw_id.c_str(), ID_SIZE);
struct conf_t conf {10, 2048, {*id}};
}
is that you cannot initialize an array element of type const unsigned char with an lvalue of type unsigned char[16].
What you need to initialize your member, is to use the correct initialization syntax with curly braces { vals... }, and use the correct types on the initialization values. Thismeans, that you must dereference your id variable: {*id}
And everything compiles fine now. You can see a live example here