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.
CodePudding user response:
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
CodePudding user response:
Try either of these syntaxes:
struct conf_t {
const unsigned int a;
const unsigned int b;
const unsigned char id[ID_SIZE];
};
conf_t syntax_1 = { 10, 1, { 'a', 'b', 'c' }}; // an array needs its own {}
conf_t syntax_2 = { 10, 1, "hello" }; // an array of char can be a string.
// make sure you have room for the
// null termination!