Initialize a struct with data from an array - c

I'd like to keep my keywords in a struct:
typedef const char* label;
const struct keywords_t
{
label init;
label moveUnit;
} keywords;
But I'd like to be able to check whether a keyword is valid with a for loop, so I tried to initialize the struct like this:
const label allowed_keywords[] =
{
"INIT",
"MOVE"
};
const struct keywords_t keywords =
{
allowed_keywords[0],
allowed_keywords[1]
};
This gives me an
error: initializer element is not constant
What am I doing wrong? The whole array is constant, though.

In C constvariables are not constants, they are simply variables that cannot be changed. Thus their value cannot be used in constant expressions, like in struct initializer.
One work-around could be to use preprocessor defines for initializers:
#define KEYWORD_INIT "INIT"
#define KEYWORD_MOVE "MOVE"
const label allowed_keywords[] =
{
KEYWORD_INIT,
KEYWORD_MOVE
};
const struct keywords_t keywords =
{
KEYWORD_INIT,
KEYWORD_MOVE
};
Other approach could be to use combination of enumeration and array:
typedef enum {
KEYWORD_INIT,
KEYWORD_MOVE
} label;
const char * const keyword_strings[] = {
"INIT",
"MOVE"
};
const struct keywords_t keywords =
{
KEYWORD_INIT,
KEYWORD_MOVE
};
// Getting keyword string would be like this:
// keyword_strings[keywords.moveUnit]

I might be the best resource for this, but both Arrays and Structs are simple memory mapping tools.
An array of char * and a struct containing the same number of char * should have the same memory structure and the same memory footprint.
So, in practice, all you need is to cast the array into the struct rather then anything else (this will also save you memory, although this is probably not so important).
i.e.
const label allowed_keywords[] =
{
"INIT",
"MOVE"
};
typedef const char* label;
const struct keywords_t
{
label init;
label moveUnit;
};
// struct keywords_t * keywords = (struct keywords_t *) allowed_keywords;
#define keywords ((struct keywords_t *) allowed_keywords)
A few things:
this needs to be tested.
I would avoid using the _t for the struct keywords_t, as _t is reserved for POSIX types. I use _s for structs and _pt for pointers... but that's up to you.

Related

C struct initialization done "recursively"

I've newly come across an example of C-struct initialization that was explained by this question.
What I don't understand is what appears to be recursive definition; this is from MicroPython/objtype.c
typedef struct _mp_obj_type_t mp_obj_type_t;
const mp_obj_type_t mp_type_type = { // <-- SAME SYMBOL DEFINED HERE . . .
{ &mp_type_type }, // <-- IS USED HERE
.name = MP_QSTR_type,
.print = type_print,
.make_new = type_make_new,
.call = type_call,
.unary_op = mp_generic_unary_op,
.attr = type_attr,
};
The fields specified by .<some_field> I understand (see link in first sentence).
But about the "recursive" initialization?
There are other instances in the MicroPython code that use this syntax:
const mp_obj_type_t pyb_led_type = {
{ &mp_type_type }, <-- SAME SYMBOL AS ABOVE
.name = MP_QSTR_LED,
.print = led_obj_print,
.make_new = led_obj_make_new,
.locals_dict = (mp_obj_t)&led_locals_dict,
};
This makes more sense: the struct pyb_led_type is initialized with defaults set in struct mp_type_type and certain fields are changed from the default.
But what about const mp_obj_type_t mp_type_type?
The struct mp_type_type is defaulted to the values of . . . struct mp_type_type . . . ???
The pre-processed output is identical to .c.
What's going on here?
Here's few fields of the struct
struct _mp_obj_type_t {
// A type is an object so must start with this entry, which points to mp_type_type.
mp_obj_base_t base;
// The name of this type.
qstr name;
// Corresponds to __repr__ and __str__ special methods.
mp_print_fun_t print;
...
};
struct _mp_obj_base_t {
const mp_obj_type_t *type MICROPY_OBJ_BASE_ALIGNMENT;
};
typedef struct _mp_obj_base_t mp_obj_base_t;
Self-referencing structs in C
The MicroPython's code you are quoting is simply creating a self-referential struct instance, which is perfectly fine in C. Consider this example, which is pretty much you example stripped of some unnecessary parts:
#include "stdio.h"
// const base
struct A {
const struct A* base;
};
// non-const base
struct B {
const struct B* base;
};
const struct A a = { &a };
const struct B b = { &b };
int main() {
printf("%p %p\n", (void*) &a, (void*)a.base);
printf("%p %p\n", (void*) &b, (void*)b.base);
return 0;
}
Specific use in the instantiation of mp_obj_type_t structs in MicroPython's code
MicroPython project is using base pointer to implement (multiple) inheritance in Python. The base reference is a pointer to another type which is a base type ("parent" in the type hierarchy), looking at the definition of this struct:
struct _mp_obj_type_t {
// A type is an object so must start with this entry, which points to mp_type_type.
mp_obj_base_t base;
// .. many more fields
}
The case you are mentioning is mp_type_type const variable seems to be base type of all types, thus the self-reference but it makes much more sense when you look at the types that "inherit" from mp_type_type, like pyb_led_type:
const mp_obj_type_t pyb_led_type = {
{ &mp_type_type },
.name = MP_QSTR_LED,
.print = led_obj_print,
.make_new = led_obj_make_new,
.locals_dict = (mp_obj_t)&led_locals_dict, };
Objects in this system (MicroPython) start with a pointer to their type. MicroPython Types are represented as objects of type mp_type_type. An mp_type_type is a type itself so its type field points to itself. (Concept is perhaps best illustrated in the Smalltalk literature. cf: http://pharo.gforge.inria.fr/PBE1/PBE1ch14.html perhaps.)
const mp_obj_type_t mp_type_type = { // <-- SAME SYMBOL DEFINED HERE . . .
{ &mp_type_type }, // <-- IS USED HERE
.name = MP_QSTR_type,
...
};
The fields specified by . I understand (see link in first
sentence).
But about the "recursive" initialization?
There nothing there that could reasonably be characterized as recursive initialization. That would be initializing an object or one of its members with the value of that object, which C indeed forbids, but no such thing is in evidence.
Your example shows a member of an object being initialized with the address of that object (that's what the & operator computes). The address of an object does not depend in any way on that object's value, and it can safely be computed before the object is initialized. Such practice is not even all that uncommon, in a general sense, though it is unusual specifically to initialize part of an object with a pointer to that object.

c make a copy of an array of const structs

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().

Table in struct initialisation in C

How to initialise the table DetectionSensors in this structure:
typedef struct
{
DetectionSensor *DetectionSensors[];
unsigned char nbSensors;
} SENSOR_STRUCT;
SENSOR_STRUCT my_var = { } ?
This table contains just some DetectionSensor pointers;
You can't; the structure definition shown shouldn't compile.
typedef struct
{
DetectionSensor *DetectionSensors[]; // Not C
unsigned char nbSensors;
} SENSOR_STRUCT;
If you're trying for a flexible array member (FAM), that has to be the last field in the structure and you can't write initializers for structure containing a FAM.
Otherwise, you need to use an explicit size for the dimension of the array, or lose the array notation and use DetectionSensor *DetectionsSensors; (or conceivably, but it seems implausible) DetectionSensor **DetectionSensors;.
typedef struct
{
DetectionSensor *DetectionSensors[10]; // Use an enum or #define
unsigned char nbSensors;
} SENSOR_STRUCT;
With this, you need some DetectionSensors around:
DetectionSensor ds[10];
SENSOR_STRUCT my_var = { { &ds[0], &ds[1], &ds[2], &ds[3] }, 4 };
In general, reserve ALL_CAPS for macros (FILE and DIR notwithstanding).
If your intention is to initialise the structure with a predefined set of Detectionsensor, you can do like this.
DetectionSensor sample [] = {sensor1, sensor2];
my_var.DetectionSensors = sample;
There's no automatic constructor for C structs, first you need to build the DetectionSensors array and then assign the value of that array to the DetectionSensor variable in your SENSOR_STRUCT.
typedef struct
{
DetectionSensor * DetectionSensors;
unsigned char nbSensors;
} SENSOR_STRUCT;
DetectionSensor * sensors = ...; //get your detection sensors.
SENSOR_STRUCT my_var = {sensors, ... };
You should reserve some memory for the DetectionSensors, e.g. this way:
#define MAX_SENSORS 10
typedef struct
{
DetectionSensor *DetectionSensors[MAX_SENSORES];
unsigned char nbSensors;
} Sensor_Struct;
Sensor_Struct my_var;
myvar.DetectionSensors[0] = somePointer;
my_var.nbSensors = 1;
btw: CAPS_LOCKED_NAMES are by convention for preprocessor variables (#define SOMETHING abc)
You could provide functions to add a new sensor and even make the memory use dynamic, if you need that.

Error: initializer element is not constant - linux driver

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.)

Constructor for structs in C

Given:
struct objStruct {
int id;
int value;
};
typedef struct objStruct Object;
Is there a shortcut to allocate and initialize the object, something like a C++ constructor?
It could even be a preprocessor macro. Whatever makes the code shorter and more readable than this:
Object *newObj = malloc(sizeof(Object));
// successful allocation test snipped
newObj->id = id++;
newObj->value = myValue;
In C I typically create a function in the style of a constructor which does this. For example (error checking omitted for brevity)
Object* Object_new(int id, int value) {
Object* p = malloc(sizeof(Object));
p->id = id;
p->value = value;
return p;
}
...
Object* p1 = Object_new(id++, myValue);
In C99 and beyond, you can use a compound literal, which looks like a cast followed by an initializer in braces:
int init_value = ...;
int init_id = ...;
Object newObj1 = (Object){ .value = init_value, .id = init_id };
Object newObj2 = (Object){ .id = init_id, .value = init_value };
The latter two lines achieve the same effect - the order of the fields is not critical. That is using 'designated initializers', another C99 feature. You can create a compound literal without using designated initializers.
In C it is possible to declare an inline function with the same name as structure:
struct my
{
int a;
};
inline struct my* my(int* a)
{
return (struct my*)(a);
}
//somewhere in code
int num = 123;
struct my *sample = my(&num);
//somewhere in code
It looks pretty similar to C++ ctors.
struct thingy {
char * label;
int x;
};
#define declare_thingy( name, label, val) struct thingy name = { label, val }
struct thingy * new_thingy(const char * label, int val) {
struct thingy * p = malloc(sizeof(struct thingy));
if (p) {
p->label = label;
p->val = val;
}
return p;
}
You really have to distinguish initialization of static or auto variables and dynamic allocation on the head. For the first, do named initializers, for the second a well specified init function.
All that can be nicely
packed into macros do give you an easy static/auto intialization and something similar to new in C++.
If you are looking for an object oriented "emulation" over C, I strongly recommend the GObject Type System [1], it's mature and largely used by GTK for instance.
GLib [2] has also a nice slice allocator for small objects, currently used by GNOME.
[1] GObject Reference Manual
[2] GLib Memory Slices

Resources