I'm trying to initialize a structure member that needs to point to an array of pointers. The idea is to declare the array of structures statically to avoid initialization overhead since all the data is fixed and known at compile time.
Unfortunately, I cannot get the code to compile under Visual Studio 2015. The code listed below produces the following error: C2099: initializer is not a constant. Which seems odd because list is only initialized with a fixed sized list of string literals.
#define DATA_LIST { \
L"some", \
L"example", \
L"data", \
L"in a list", \
NULL \
}
#define INFO_LIST { \
L"another", \
L"list", \
L"with", \
L"some", \
L"info", \
NULL \
}
typedef struct data {
unsigned int flag;
const wchar_t **list;
} dataset, *pdataset;
static dataset somedata[] = {
{ .flag = 2,
.list = (const wchar_t *[])DATA_LIST // C2099
},
{ .flag = 4,
.list = (const wchar_t *[])INFO_LIST // C2099
}
};
I've also tried to use a pointer to a flexible array (const wchar_t *list[];). Not the ideal solution because somedata will no longer be able to be declared as an array of structures. Next to that, it will also produce a warning (C4200: nonstandard extension used: zero-sized array in struct/union).
typedef struct data {
unsigned int flag;
const wchar_t *list[]; // C4200 (somedata can no longer be an array of structures)
} dataset, *pdataset;
static dataset somedata = {
.flag = 2,
.list = DATA_LIST
};
Another idea was to define list as a pointer to a fixed size array of pointers. But this requires the dataset structure to be defined with a list member that is large enough to hold the largest list. Also not ideal when there are lots of small lists and one single large list.
typedef struct data {
unsigned int flag;
const wchar_t *list[sizeof (wchar_t *[])INFO_LIST / sizeof *(wchar_t *[])INFO_LIST];
} dataset, *pdataset;
static dataset somedata[] = {
{ .flag = 2,
.list = DATA_LIST
},
{ .flag = 4,
.list = INFO_LIST
}
};
Maybe I'm overseeing something or is there some language extension feature available that can provide an elegant solution? Any suggestions are welcome.
Note: even though the visual-c++ tag is added, the code is compiled as C code.
Another interesting thing to add which might be related, is that when somedata is declared as non-static (thus without the static keyword), the compiler will produce some warnings but is able to compile the code. By declaring somedata as non-static, the constraint is removed that forces the data used for initializing somedata to be known at compile time.
As indicated by the compilation warnings, it seems that the compiler temporarily stores the address of the list of string literals in an automatic variable before initializing the list member with it. This remains speculation, though. Maybe someone experienced can shed some light on what is actually happening here.
typedef struct data {
unsigned int flag;
const wchar_t **list;
} dataset, *pdataset;
// C4221: nonstandard extension used: 'list': cannot be initialized using
// address of automatic variable '$S1'
// C4204: nonstandard extension used: non-constant aggregate initializer
dataset somedata = {
.flag = 2,
.list = (const wchar_t *[])DATA_LIST // note: see declaration of '$S1'
};
Last but not least, when using a temporary variable initialized with the address of the list of string literals to initialize the list member, the code finally compiles fine without any warnings or errors.
static const wchar_t *temp[] = DATA_LIST;
static dataset somedata = {
.flag = 2,
.list = temp
};
But when declaring temp as a pointer to a pointer and typecasting the list of string literals, the code can no longer be compiled as the expression that initializes list becomes marked as an active error: expression must have a constant value
static const wchar_t **temp = (const wchar_t *[])DATA_LIST;
static dataset somedata = {
.flag = 2,
.list = temp // marked as active error
};
If I then decide to make somedata non-static again, the expression is no longer marked as an active error. But when trying to compile the code, the following error comes back up again: C2099: initializer is not a constant
I'm wondering if Visual Studio 2017 behaves the same way and if there is an alternative method available to organize and process the data by similar means.
MSVC has poor compliance to the C Standard. As a workaround you can use named objects instead of compound literals:
static const wchar_t *x_data_list[] = DATA_LIST;
static const wchar_t *x_info_list[] = INFO_LIST;
static dataset somedata[] = {
{ .flag = 2,
.list = x_data_list
},
{ .flag = 4,
.list = x_info_list
}
};
I'm not sure whether you intentionally made your lists non-const, but if you are not planning to write to x_data_list at runtime then you can make it const and give the .list member the type const wchar_t * const *.
Related
I am new to C and using it to program a Nordic nrf52 chip. I believe my problem is a general C one though rather than application.
I am setting up an array of structs using macros predefined in the chip SDK. Using those macros in the array initialisation works, but doing element by element does not.
So, the following works:
nrf_twi_mngr_transfer_t transfers_1[2] = { \
NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP), \
NRF_TWI_MNGR_READ (MSBARO5X_0_ADDR , &p_buffer[0], sizeof(p_buffer), 0)
};
Where:
typedef struct {
uint8_t * p_data; ///< Pointer to the buffer holding the data.
uint8_t length; ///< Number of bytes to transfer.
uint8_t operation; ///< Device address combined with transfer direction.
uint8_t flags; ///< Transfer flags (see #ref NRF_TWI_MNGR_NO_STOP).
} nrf_twi_mngr_transfer_t;
NRF_TWI_WRITE and _READ are macros that use further macros, for example:
#define NRF_TWI_MNGR_WRITE(address, p_data, length, flags) \
NRF_TWI_MNGR_TRANSFER(NRF_TWI_MNGR_WRITE_OP(address), p_data, length, flags)
which uses
#define NRF_TWI_MNGR_WRITE_OP(address) (((address) << 1) | 0)
and
#define NRF_TWI_MNGR_TRANSFER(_operation, _p_data, _length, _flags) \
{ \
.p_data = (uint8_t *)(_p_data), \
.length = _length, \
.operation = _operation, \
.flags = _flags \
}
What I want to do is change individual items in this array, for example:
transfers_1[0] = NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP);
However when I do that, I get the error "expected an expression".
MSBARO5X_0_ADDR is also defined in a define statement:
#define MSBARO5X_0_ADDR 0x76
If I replace this in any of the above code with a variable, I get the same "expected an expression" error. I suspect the two problems I have are due to the same lack of understanding on my part. SO forgive me for combining the two in a single post.
So the questions are:
-Why am I getting this error?
-Is it possible to change individual items in my array, and if so how?
-Is it possible to use a variable in place of the MSBARO5X_ADDR, and if so how?
Many thanks!
Ultimately, the macro expands into a brace enclosed initializer. Such a thing is not an expression, so it cannot be used as the right hand side of plain assignment (assignment and initialization are different things). It will work as part of a larger initializer, but not the way you try to use it unmodified.
But all is not lost. The syntax of the initializer implies c99 support. So we can use a trick. Structure objects can be assigned to eachother. So we need only obtain an object from somewhere. We can use a compound literal in order to create said object:
transfers_1[0] = (nrf_twi_mngr_transfer_t)NRF_TWI_MNGR_WRITE(/*Your arguments*/);
If you define the value of a structure the moment you declare it, the compiler will infer the type of the structure from the declaration. So this here will compile:
struct coordinates {
int x;
int y;
};
struct coordinates origin = { 10, 20 }; // This is OK
But if you assign a value to a previously declared variable, the compiler cannot infer its type. This code won't compile:
struct coordinates origin;
origin = { 10, 20 }; // ERROR! The type of the rvalue is unknown!
The type is unknown, because two structures are not equivalent in C just because they have the same members. E.g. this is legal in C:
struct coordinates {
int x;
int y;
};
struct dayOfYear {
int day;
int month;
};
Now what would { 5, 8 } be? The coordinates (5/8) or the 5th of August? It could be both. All that he compiler knows is that it is a struct of type { int, int }. Yet this does not define a type in C. The following is possible in some languages but it's not possible in C:
struct dayOfYear date = { 2, 3 };
struct coordinates cords = date; // ERROR!
Despite the fact that both structures are of type { int, int }, for the compiler struct dayOfYear and struct coordinates are two completely distinct and unrelated data types.
If you want to declare a hardcoded struct value, you need to tell the compiler what kind of struct that is:
struct coordinates origin;
origin = (struct coordinates){ 10, 20 }; // This is OK
Your NRF_TWI_MNGR_TRANSFER defines a hardcoded struct but only when you use that in a definition the compiler knows the type. If you try to use it as an assignment, you need to cast to the correct type.
transfers_1[0] = (nrf_twi_mngr_transfer_t)NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP);
Which is not really a cast, even though it has the same syntax. In fact this is just telling the compiler how to interpret the following data.
In an embedded project, I use a library that provides a macro for initializing a structure. This provides reasonable defaults, but the defaults depend on other parameters. I want to override one or more values of this designated initializer, because initializing the values afterwards generates overhead.
Ideally, I don't want to copy-paste all of the macro's, because I then have to manage third-party code. If the library changes it's defaults, I don't want to do that too.
Is there a way of combining or overriding designated initializers, so there is no overhead? The code has to be C99 compliant and portable.
Some example code to demonstrate the issue:
#if SITUATION
#define LIBRARY_DEFAULTS \
{ \
.field_a = 1, \
.field_b = 2, \
.field_c = 3 \
}
#else
#define LIBRARY_DEFAULTS \
{ \
.field_a = 100, \
.field_b = 200, \
.field_c = 300, \
.field_d = 400, \
.field_e = 500 \
}
#endif
/* The following is what I want (or similar), but (of course) doesn't
work. */
// #define MY_DEFAULTS = LIBRARY_DEFAULTS + { .field_a = 100 }
int main(void) {
/* The exact definition of something also depends on situation. */
struct something library_thing = LIBRARY_DEFAULTS;
/* This generates overhead, and I want to avoid this. It is certain
that the field exists. */
library_thing.field_a = 100;
}
You could wrap your library_thing in an outer structure, and do your overrides from the outer structure's initializer:
#include <stdio.h>
struct foo {
int a,b,c;
};
#define FOO_DEFAULTS { .a = 1, .b = 2, .c = 3 }
int main() {
struct {
struct foo x;
} baz = {
.x = FOO_DEFAULTS,
.x.a = 4,
};
printf("%d\n", baz.x.a); // prints 4
}
In fact, you can even do
.x = FOO_DEFAULTS,
.x = {.a = 4},
if you need to really "merge" two initializers.
This compiles fine on Clang (7.0.2) but generates a warning under -Winitializer-overrides. Checking the generated code confirms that the structure is initialized with 4, 2, 3 so there is no additional overhead from this trick.
Here's one possible solution. First remove the braces from the macro
#define LIBRARY_DEFAULTS .a=1, .b=2, .c=3
Then for variables where the defaults are ok, you enclose the macro in braces
struct something standard = { LIBRARY_DEFAULTS };
For a variable where the defaults need tweaking, add some additional initializers
struct something tweaked = { LIBRARY_DEFAULTS, .a=100 };
Why does this work? Section 6.7.9 of the C specification discusses the use of designators in initialization lists and has this to say about specifying the same designator more than once:
19 The initialization shall occur in initializer list order, each
initializer provided for a particular subobject overriding any
previously listed initializer for the same subobject;151)
all subobjects that are not initialized explicitly shall be
initialized implicitly the same as objects that have static storage
duration.
and note 151 says this
151) Any initializer for the subobject which is overridden and so not
used to initialize that subobject might not be evaluated at all.
Which is to say that the compiler is required to use the last designated initializer, and may implement this solution without any overhead.
I have an array of structs and some of the struct members are constant
I would like to make a deep copy of the array.
The copy will also have the same members of the struct be constants.
How do I initialize the values into the new array without violating the const directive.
Below is an excerpt of my code. The actual program is quite long but I think I've included all the relevant code. In this example keys is declared as a global variable that I would like to make new instances from. I'm treating it sort of like a template with preset values.
When I try to compile this in Debian with gcc I get the following error:
main.c:216:9: error: assignment of read-only location ‘*(new_keys + (unsigned int)((unsigned int)index * 540u))’make: *** [main.o] Error 1
The makefile is using the following qualifier:
CFLAGS=-c -g -std=gnu99 -D_XOPEN_SOURCE=700
Interestingly. I can compile the same code in Xcode without an error or warning even with Xcode set for C Language Dialect GNU99[-std=gnu99]
I can make my code work simply by getting rid of the const keywords. But these values truly should be const. Once these arrays are initialized they will never change. I would like to understand how to do this properly and also I would like to know why this works in Xcode and not gcc.
Header File
typedef struct {
char * name;
char * alias;
int number;
} pair_int_t;
typedef struct {
const char * const name;
const kind_t kind; // kind is enum type
const pair_int_t * const enum_array;
bool received;
const char * const alias;
} key_descriptor_t;
typedef key_descriptor_t keys_descriptor_t[_END_OF_KEYS+1];
body of .c program before main()
const pair_int_t command_list[] = {
{.name = "numeric data response", .alias = "num", .number = RES_NUMERIC_DATA},
{.name = "read attribute", .alias = "readat", .number = CMD_READ_ATTR},
//..
}
// declare a global variable *keys* with constants assigned to it
key_descriptor_t keys[] = {
[_COMMAND] = {.name = "command", .kind = ENUMERATED, .alias = "com", .enum_array = command_list},
[_RESPONSE] = {.name = "response", .kind = ENUMERATED, .alias = "res", .enum_array = command_list},
[_UNIT] = {.name = "unit number", .kind = NUMBER, .alias = "uni", .enum_array = NULL},
//..
}
int initialize_new_keys(keys_descriptor_t new_keys) {
int index;
for (index = _FIRST_KEY; index <= _END_OF_KEYS; index++){
new_keys[index] = keys[index]; // line 216, keys is a global variable
}
return index;
}
main program
int main(int argc, const char * argv[]){
keys_descriptor_t 2nd_set_of_keys;
initialize_new_keys(2nd_set_of_keys);
}
You can only initialize const variables at the time you define them. Creating an array with const members, sending it to a function, and then trying to assign to those members signifies that you didn't really mean const in the first place. There's no syntax in C for "const except for the first assignment".
A reasonable alternative is to make an opaque type, encapsulate the definition in a separate translation unit, and then access all the members purely through an interface of functions. That way, even though things may not be const, they still can't be changed (except through deliberate subversion, which is at least no better than not calling things const in the first place) because no code that uses them has access to the definition of the struct, or therefore to the members.
EDIT: In response to the question in the comment, "is there a way to create and initialize one complex constant variable to the value of another existing constant variable of the same type?", there sure is - just initialize it normally:
struct mystruct {
const int a;
const int b;
};
static const struct mystruct m = {1, 2};
int main(void) {
struct mystruct n = m;
return 0;
}
Obviously the more complex your struct is, the more complex this may become.
"2nd_set_of_keys" is a struct, it should be a static array (or can be a pointer and reserve memory dynamically), the same problem occurs with the "new_keys" parameter.
Although a little weird, you can copy data to const variables (overriding the const verification) by using memcpy().
I am really not able to solve this issue.
error: initializer element is not constant
error: (near initialization for tca6507_leds1.leds.num_leds)
I think the problem is related to struct led_info *leds inside led_platform_data. Is this somehow not a const since it is a pointer? I am particularly baffled since led_platform_data and led_info are part of the linux kernel. tca6507_platform_data is also a part of a driver that is included in the kernel source.
Here is my initialization:
static struct led_info tca6507_led_infos[] = {
{
.name = "left_blue",
.default_trigger = "heartbeat",
},
};
static struct led_platform_data tca6507_leds2 = {
.leds = tca6507_led_infos,
};
struct tca6507_platform_data tca6507_leds1 = {
.leds = tca6507_leds1
};
All the structs are defined in header files that I did not write.
struct led_info {
const char *name;
const char *default_trigger;
int flags;
};
struct led_platform_data {
int num_leds;
struct led_info *leds;
};
struct tca6507_platform_data {
struct led_platform_data leds;
#ifdef CONFIG_GPIOLIB
int gpio_base;
void (*setup)(unsigned gpio_base, unsigned ngpio);
#endif
};
The problem is right in the middle of this three line bit:
struct tca6507_platform_data tca6507_leds1 = {
.leds = tca6507_leds1
};
What is the (compile time) value of tca6507_leds1? Note that it is a structure, not an array.
Compare that with the (valid):
static struct led_platform_data tca6507_leds2 = {
.leds = tca6507_led_infos,
};
What is the (compile time) value of tca6507_led_infos? (Note that it is an array, and the "value" of an array is the address of its first element.) And most importantly (perhaps I should not have buried the lede :-) ), compare with the (also valid):
static struct led_info tca6507_led_infos[] = {
{
.name = "left_blue",
.default_trigger = "heartbeat",
},
};
Note that instead of using the value of a variable, the initializer here is a brace-enclosed list of items. This (like the failing case) is an instance of struct led_info, which must contain one actual struct led_platform_data instance (not a pointer to one-or-more, as is used in struct led_platform_data).
(The above is meant as an exercise. The answer is, the value of a structure is the value of the structure—but that is not a compile-time constant. Moreover, you are trying to use the value of the structure that you have not yet finished initializing in the first place. You need X to set X but you have to find X first, which you do by finding X, and there's no end to the recursion.)
Can someone tell me the difference between these two versions of a declaration of a structure?
struct S
{
uint8_t a;
};
and
const struct S
{
uint8_t a;
}
Followed by:
void main(void)
{
struct S s = {1};
s.a++;
}
Hint, i've tried both versions for S in Visual Studio C++ 2010 Express so I know that both compile with errors.
Is the "const struct" doing nothing at all? "const struct S s = {1};" certainly does, but that's not the issue at the moment.
Regards
Rich
/********************************************/
I've just worked out what
const struct <typename> <{type}> <variable instances a, b, .., z>;
is doing:
When const is present before the "struct", all variable instances are const, as though they'd be defined with:
const struct <typename> a, b, z;
So it does do something, but not when there's no instance definitions in-line with the struct declaration.
Rich
A declaration of structure just defines the data type.
const qualifier appies to a variable not a data type. So adding const preceeding a struct declaration should be redundant at the most.
With:
const struct S
{
uint8_t a;
};
The const qualifier there is nonsense, and may even cause a compilation error with some C compilers. gcc issues a warning.
The intent appears to be to declare the data type struct S. In this case, the proper syntax is:
struct S
{
uint8_t a;
};
const struct S
{
uint8_t a;
};
is not a valid construct.
This
const struct S
{
uint8_t a;
} x;
could possibly be valid as you're declaring a variable x that is now const, meaning it cannot change.
The const qualifier applies to variables or members.
To instantiate a const variable, just specify const during instantiation.
What const does, is:
during compilation, verify that only reads are performed on the const variables
if the const variable is created with a value which can be resolved during compilation, put the variable in the program memory
When const is applied to members, like in:
struct T {
int const i;
int j;
};
You can only (legally) assign the value i during the creation of the structure.
You may be able to modify a const value (if the program memory sits in RAM and not ROM) by casting it to a non-const type (const-cast) but this is something you shouldn't do.
The typical usage of const-cast is when you use a library which does not specify the constness in function declarations, and your code does. At this point if you want to use it you have to trust it and cast parameters before calling its functions.
It is nonsense to use const keyword before struct.
If you are using gcc compiler, it shows you the following warning:
warning: useless type qualifier in empty declaration [enabled by default]
This is the only use I can think of:
const struct S {
int a;
int b;
} s;
This declares a struct and immediately creates an instance for it named s and at this point, a and b in s are initialized to 0 (please note that at this point s is a global variable in the translation unit which it has been declared in and can be externally linked to).
printf("a = %d\t b = %d\n", s.a, s.b); // a = 0 b = 0
If you try to set members of s, you will fail:
s.a = 1; //error: assignment of member ‘a’ in read-only object
So, s is not really useful here...unless you do something like:
const struct S {
int a;
int b;
} s = { 1, 2 };
Now let's create another instance of the same struct (declaration is still same as above):
struct S other;
other.a = 1;
other.b = 2;
printf("a = %d\t b = %d\n", other.a, other.b); // a = 1 b = 2
The compiler will not complain anymore as other is not const! only s is const!
Now, what that const do, you may ask? let's try to change s:
s = other; // error: assignment of read-only variable ‘s’
That is all to it. If you did not need the compiler to allocate storage for s at the point of declaration and still needed an instance of s to be const you would just add const at the point of instantiating struct S (note the capital S!!)
Bonus 1
const struct S {
int a;
int b;
};
note that there is no small s anymore. At this point, GCC will warn you that const qualifier does not do anything!!!!
Bonus 2
If you want every instance of the struct to be const, that is its members can only be initialized at the point of definition you can do like (using typedef):
typedef const struct S {
int a;
int b;
} s;
// The wrong way
s thisIsAnS;
thisIsAnS.a = 1; //error: assignment of member ‘a’ in read-only object
// The correct way
s thisIsAnS = { 1 , 2 }; //compiles fine, but you can not change a or b anymore
Conclusion
To me, this is just syntactic sugar and only adds unnecessary complexity to the code. But who am I to judge...
When you declare
const var;
then it allocate the some memory space for it but
struct var;
it was just an declaration compiler does not allocate any space for it.
so it shows the error and in const struct you didn't declare any varible see the code so it shows error.