How can an array of structs be initialized using a const struct in global scope? - c

I want to use code similar to the following (but a lot more complex - this is a simplified example) to initialize an array of structures, but during compilation I get the error "expression must have a constant value".
typedef struct
{
int x;
int y;
} windowStruct_t;
static const windowStruct_t windowStructInit =
{
.x = 3,
.y = 5,
};
// These get defined differently at times. This is simplified for the example.
#define NUM_ARRAY_ELEMENTS (2)
#define REPEAT_NUM_ARRAY_ELEMENTS_TIMES(x) (x),(x)
// The following line causes the error "expression must have a constant value" twice.
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ REPEAT_NUM_ARRAY_ELEMENTS_TIMES( windowStructInit ) };
void someFunction( void )
{
volatile int x = windowStruct[0].x;
}
void anotherFunction( void )
{
volatile int y = windowStruct[1].y;
}
Manually expanding the macro and replacing the line that causes the error with the following gives the same result:
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ windowStructInit, windowStructInit };
But this compiles without error:
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ { .x = 3, .y = 5 }, { .x = 3, .y = 5 } };
If I move the array declaration inside of function scope, it compiles without errors (I am ignoring the fact that someFunction() and anotherFunction() now access different arrays and that their lifetimes are different):
void someFunction( void )
{
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ REPEAT_NUM_ARRAY_ELEMENTS_TIMES( windowStructInit ) };
volatile int x = windowStruct[0].x;
}
void anotherFunction( void )
{
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ REPEAT_NUM_ARRAY_ELEMENTS_TIMES( windowStructInit ) };
volatile int y = windowStruct[1].y;
}
Leaving the array declarations inside of function scope, if they are declared to be "static", the error message comes back:
void someFunction( void )
{
static windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ REPEAT_NUM_ARRAY_ELEMENTS_TIMES( windowStructInit ) };
volatile int x = windowStruct[0].x;
}
So it seems that when the arrays are declared as automatic variables (on the stack) that they can be initialized in a way that isn't allowed when the memory allocation is static (whether inside function scope or in global scope where the allocation is static even without the "static" keyword). Is there a way to initialize the array in global scope using a const struct as in the original example?
I am using C, not C++. I don't want to use dynamic memory allocation. The compiler is TI's ARM compiler V16.6.0.STS as included in their Code Composer Studio environment.

A const object is not a C constant. Instead use constants which is required for non-automatic storage objects.
Define an initializer { .x = 3, .y = 5 }
typedef struct windowStruct_s {
int x;
int y;
} windowStruct_t;
#define windowStruct_t_default_initializer { .x = 3, .y = 5 }
#define NUM_ARRAY_ELEMENTS (2)
#define REPEAT_NUM_ARRAY_ELEMENTS_TIMES(x) x, x /* no () */
windowStruct_t windowStruct[NUM_ARRAY_ELEMENTS] = {
REPEAT_NUM_ARRAY_ELEMENTS_TIMES(windowStruct_t_default_initializer) };
int someFunction(void) {
volatile int x = windowStruct[0].x;
return x;
}
int anotherFunction(void) {
volatile int y = windowStruct[1].y;
return y;
}

Related

Array of jump tables in C

I'm trying to optimize access to some jump tables I have made, they are as follows:
int (*const usart_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[USART_READ_WRITE_CLEAR])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
As you can see, the functions are for accessing a usart peripheral on a hardware level and are arranged in the table in the order of read/write/clear.
What I am attempting to do is have another jump table of jump tables, this way I can either run through initializing all the usart's registers in startup or simply change a single register later if desired.
i.e.
<datatype> (*usart_peripheral_table[<number of jump tables>])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
This way I can expose that table to my middleware layer, which will help maintain a standard across changing HALs, and also I can use a define to index this table i.e.
fn_ptr = usart_peripheral_table[CTRL_TABLE]
fn_ptr[WRITE](bitmask);
fn_ptr[READ](buffer);
As you may have already guessed, I am struggling to figure out how to construct this table. I figured it is one of two things:
Another simple array of pointers, as even a jump table itself is just an array of pointers. Hence my initialization would be:
const int* (*usart_peripheral_table[<number of jump tables])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
However this doesn't seem to be working. Then I thought:
An array of pointers to pointers. So I tried all kinds of combos:
const int**(*usart_perip...
const int**(usart_perip...
const int** (*usart_peripheral_table[<number of jump tables])() =
{&usart_ctrl_table, &usart_frame_table[0], usart_trig_ctrl_table};
Nothing seems to work. Do I need to store the address of the lower jump tables in yet another pointer before assigning that variable to a pointer-to-pointer array? i.e.
int* fn_ptr = usart_ctrl_table;
<dataytype>(*const usart_periph[<number>])() = {fn_ptr};
Thanks in advance, any help would be greatly appreciated.
MM25
EDIT:
const int** (*const peripheral_table[1])() =
{&usart_ctrl_table[0]};
const int** (*const peripheral_table[1])() =
{usart_ctrl_table};
The above both give the error "initialization from incomaptible pointer type", as do all other combinations I have tried
You might find that defining a typedef for your function pointers makes your code easier to read and maintain (although I’ve seen people recommend against it too):
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
uart_ctl_func uart_ctl_jump_table[][UART_RWC] = {
{ uart_read, uart_write, uart_clear },
{ uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_jump_table[0][1](); // Write.
uart_ctl_jump_table[1][0](); // Read.
uart_ctl_jump_table[1][2](); // Clear.
return EXIT_SUCCESS;
}
The next step might be to make the jump table a struct so you end up writing Uart_ctl_table.frame.read(), or to at least define an enum for the constants.
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
typedef struct {
uart_ctl_func read;
uart_ctl_func write;
uart_ctl_func clear;
} uart_ctl_set_t;
typedef struct {
uart_ctl_set_t ctrl;
uart_ctl_set_t frame;
uart_ctl_set_t trig;
} uart_ctl_table_t;
const uart_ctl_table_t uart_ctl_table = {
.ctrl = { uart_read, uart_write, uart_clear },
.frame = { uart_read, uart_write, uart_clear },
.trig = { uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_table.ctrl.write(); // Write.
uart_ctl_table.frame.read(); // Read.
uart_ctl_table.trig.clear(); // Clear.
return EXIT_SUCCESS;
}
Just add a * like you added [] when defining an array.
int zg_usartCtrlRead();
int zg_usartCtrlWrite();
int zg_usartCtrlClr();
int zg_usartFrameRead();
int zg_usartFrameWrite();
int zg_usartFrameClr();
int zg_usartTrigctrlRead();
int zg_usartTrigctrlWrite();
int zg_usartTrigctrlClr();
int (*const usart_ctrl_table[])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
int (* const * const usart_peripheral_table[])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
Usage:
usart_peripheral_table[1][2](5, 1, 3, 5, 6);
Btw, an empty parameter list on function declaration () means unspecified number and type of arguments. Do (void) if you want no arguments passed to your function.
This:
const int* (*usart_peripheral_table[<number of jump tables])();
Is an array of functions pointers that take unspecified number of arguments and return a pointer to constant integer.
This:
const int** (*usart_peripheral_table[<number of jump tables])()
Is an array of function pointers that take unspecified number of arguments and return a pointer to a pointer to a constant integer.
You can also go with a 2D array:
int (* const usart_peripheral_table_2d[][3])() = {
{
zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr,
}, {
zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr,
}, {
zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr,
},
};
But maybe you want to write accessor functions that will return a pointer to an array of functions. Nothing simpler!
#include <stddef.h>
int (*usart_ctrl_table_get(size_t idx))() {
return usart_ctrl_table[idx];
}
int (*usart_frame_table_get(size_t idx))() {
return usart_frame_table[idx];
}
int (*usart_trig_ctrl_table_get(size_t idx))() {
return usart_trig_ctrl_table[idx];
}
int (* const (* const usart_peripheral_table_indirect[])(size_t))() = {
usart_ctrl_table_get,
usart_frame_table_get,
usart_trig_ctrl_table_get,
};
Usage sample:
int main() {
usart_peripheral_table_indirect[2](1)();
}

How do I create an Array of Objects in C?

I'm new to C, coming from a language like javascript the amount of types, keywords etc. in the language are painfully confusing.
In javascript I can create an array of objects like so.
arrayOfObjectsInsideJavascript = [
{ s:"ejf09j290fj390j2f09", f=0 },
{ s:"dj320992209920209dj", f=0 }
]
From what I've read it seems that I'll need to be using typedefand orstructs.
I've tried:
typedef struct[] = {
{ s:"ejf09j290fj390j2f09", f=0 },
{ s:"dj320992209920209dj", f=0 }
}
struct[] = {
{ s:"ejf09j290fj390j2f09", f=0 },
{ s:"dj320992209920209dj", f=0 }
}
typedef struct {
char[] s = "ejf09j290fj390j2f09";
int f = 0;
} objectLikeClassThingy;
What's the best way to create the object I need?
like this ?
struct {
const char *s;
double f;
} obj[] = {
{ .s = "ejf09j290fj390j2f09", .f = 0 },
{ .s = "dj320992209920209dj", .f = 0 }
};
Where JavaScript has dynamic "properties", C has static "tags". A struct type is defined as a sequence of tags, which each have a type.
For the type inside your example array
arrayOfObjectsInsideJavascript = [
{ s:"ejf09j290fj390j2f09", f=0 },
{ s:"dj320992209920209dj", f=0 }
]
your last solution started off almost correctly:
struct element {
char s[256];
int f;
};
You have two options for the type of s:
If you want to store the string inside the object, you use some array type, such as char s[256]. 256 is the length of the array, so when you use zero-terminated strings, the maximum allowed string length is 255 (which is 256, minus one for the '\0' character).
If you want to store the string outside the object, you use some pointer type. Since you want to use string literals, you should declare the tag as const char *s. Changing a string literal causes undefined behaviour, so it's best to prevent yourself from doing so.
For this answer, I'll use the first option in the examples.
If you want to define one struct, you could now write something like
struct element {
char s[256];
int f;
} one_object = {
.s = "ejf09j290fj390j2f09",
.f = 0,
};
or
struct element {
char s[256];
int f;
};
/* ... later, in a scope where `struct element` is visible ... */
struct element one_object = {
.s = "ejf09j290fj390j2f09",
.f = 0,
};
or, with a typedef,
typedef struct {
char s[256];
int f;
} your_element_type;
/* ... later, in a scope where `your_element_type` is visible ... */
your_element_type one_object = {
.s = "ejf09j290fj390j2f09",
.f = 0,
};
Note that this doesn't necessarily work with older compilers that don't support the C99 standard. In the older days, you'd have to initialise fields in order:
your_element_type one_object = { "ejf09j290fj390j2f09", 0 };
Also note that, if you're never going to refer to the type name struct element again, you don't have to name it:
struct {
char s[256];
int f;
} one_object = {
.s = "ejf09j290fj390j2f09",
.f = 0,
};
Arrays are initialised similarly (you've actually already initialised an array, namely s, with a string):
struct element {
char s[256];
int f;
} so_many_objects[] = {
{ .s = "ejf09j290fj390j2f09", .f = 0 },
{ .s = "dj320992209920209dj", .f = 0 },
};
or
struct element {
char s[256];
int f;
};
/* ... later, in a scope where `struct element` is visible ... */
struct element so_many_objects[] = {
{ .s = "ejf09j290fj390j2f09", .f = 0 },
{ .s = "dj320992209920209dj", .f = 0 },
};
or, with a typedef again,
typedef struct {
char s[256];
int f;
} your_element_type;
/* ... later, in a scope where `your_element_type` is visible ... */
your_element_type so_many_objects[] = {
{ .s = "ejf09j290fj390j2f09", .f = 0 },
{ .s = "dj320992209920209dj", .f = 0 },
};
By the way, note that we are using an incomplete type for so_many_objects; this is only possible because the compiler can see how big the array should be. In these examples, the compiler would treat your code as if you'd have written struct element so_many_objects[2]. If you think you'll have to extend the array with more objects, you'd better specify how many elements the array has (at maximum), or learn about dynamic allocation.

How do I initialize a struct using the new C99 syntax?

I'm trying to initialize a struct using the new C99 initialization syntax. However, I'm getting a compilation error "expected expression before '{' token" from GCC 4.9.2 whenever I compile code that is setup like this:
// *.h file
typedef struct
{
int x;
int y;
} SPoint;
typedef struct
{
SDL_Window* window;
SPoint position;
} SWindow;
// *.c file
SWindow* create(int x, int y) {
SWindow* window = malloc(sizeof(SWindow));
// snip
(*window) = { .window = sdlWindow,
.position = { .x = x,
.y = y }};
// snip
If I add a "(SWindow)" in front of the initializer, it compiles fine. Other than some syntactical ugliness (which if you have some advice on that, I'd appreciate it), I don't see just what I'm missing.
What am I doing wrong?
(*window) = { .window = sdlWindow,
.position = { .x = x,
.y = y }};
is not initialization. It is assignment. By using
(*window) = (SWindow) { .window = sdlWindow,
.position = { .x = x,
.y = y }};
you are asking the compiler to create a temporary object, and then using the temporary object to do the assignment.

Syntax for assigning to a struct in a struct

I have a struct Entity that is made up of Limbs and an enum, Limbs is also a struct with two items e.g.
typedef enum{ALIVE, DEAD} state;
typedef struct Limb{
int is_connected;
int is_wounded;
} Limb;
typedef struct Entity{
Limb limb_1;
Limb limb_2;
state is_alive;
} Entity;
Now lets say I have a function that's designed to assign entity particular values, what is the proper syntax to use here? My current guess is this:
void assign_entity(Entity *entity){
*entity = {
.limb_1 = { 1, 0 },
.limb_2 = { 1, 0 },
.is_alive = ALIVE
};
}
But I get an error (expected expression) when I use this syntax, what am I doing wrong here? What is the proper syntax for assigning to a struct inside a struct.
You're trying to use a compound literal but omitting the proper syntax.
It should be:
void assign_entity(Entity *entity){
*entity = ((Entity) {
.limb_1 = { 1, 0 },
.limb_2 = { 1, 0 },
.is_alive = ALIVE
});
}
Note that this requires C99 (or a suitably extended compiler, of course).
Probably too verbose for someone the code below:
void assign_entity(Entity *entity)
{
entity->limp_1.is_connected = 1;
entity->limp_1.is_wounded= 0;
entity->limp_2.is_connected = 1;
entity->limp_2.is_wounded= 0;
entity->is_alive = ALIVE;
}
If you have already allocated memory at the address pointed to by entity and all you're trying to do is "assign particular values", then you would do it as follows:
void assign_entity(Entity *entity)
{
entity->limb_1 = ( 1, 0 );
entity->limb_2 = ( 1, 0 );
entity->is_alive = ALIVE;
}
Or, if you want to roll it all up into one line:
void assign_entity(Entity *entity)
{
*entity = ((1, 0), (1, 0), ALIVE);
}
Designated initializer syntax can only be used in an initialization.
One way to do what you want would be:
Entity const new = {
.limb_1 = { 1, 0 },
.limb_2 = { 1, 0 },
.is_alive = ALIVE
};
*entity = new;

Problems Initializing Structures

Here are (some of) the structures that I am using; they are in a .h file:
struct rss_s {
Radio_types device_type; // Its device_type which is defined by the typedef above Radio_Types
char * device_info; // some thing about the radio NAV/COM/etc.
char * device_model; // the Manufactures part/model number.
char * device_serial; // the device's serial number..
int power_48v; // power to the unit..
int power_400hz;
int panel_lamps; // turn off or on the Panel Lamps only
void * radio_info;
};
typedef struct tuner_s { // when we talk about 'sub-radios' we are really saying how many tuners are there??
char * device_name; // OS-name
int frequency[tuned];
int power;
int dial_lamp;
int fd[ ]; // file descriptors
}tuner;
//// 614L8 ::= C614L8
typedef enum Lp_Sw_614L8 { OFF_loop, LEFT, RIGHT, SLEW_LEFT, SLEW_RIGHT } loopsw_614L8;
typedef enum Mo_Sw_614L8 { OFF_614L8, ADF, ANT, LOOP } modesw_614L8;
struct radio_s_614L8 {
loopsw_614L8 loop_sw_614L8;
modesw_614L8 mode_sw_614l8;
int sw_band;
int sw_bfo;
int meter;
tuner * Tuner;
int tuners;
};
Now file main.c, which has all of the normal includes:
// Radio 614L8<br>
static struct radio_s_614L8 radio_614L8 = { { .Tuner = tuner_614L8, .tuners = DIM( tuner_C_614L8 ) } };
static tuner tuner_614L8 = { { .device_name = "/dev/TBD", } };
static struct rss_s radios[] = {
{ C614L8, "ADF", "614L8", "8384", & radio_C_614L8,},};
// now comes the normal main()
The errors that I have:
error: field name not in record or union initializer
error: (near initialization for ‘radio_614L8.loop_sw_614L8’)
error: ‘tuner_614L8’ undeclared here (not in a function)
error: field name not in record or union initializer
error: (near initialization for ‘radio_614L8.loop_sw_614L8’)
error: ‘tuner_C_614L8’ undeclared here (not in a function)
error: field name not in record or union initializer
error: (near initialization for‘tuner_614L8.device_name’)
error: ‘radio_C_614L8’ undeclared here (not in a function)
You currently have:
static struct radio_s_614L8 radio_614L8 = { { .Tuner = tuner_614L8, .tuners = DIM( tuner_C_614L8 ) } };
static tuner tuner_614L8 = { { .device_name = "/dev/TBD", } };
You need:
static tuner tuner_614L8 = { .device_name = "/dev/TBD", };
static struct radio_s_614L8 radio_614L8 = { .Tuner = &tuner_614L8, .tuners = 1 };
You can't refer to a variable like tuner_614L8 until you've defined or declared it. You shouldn't try to make a non-array into an array, either. You do need to take the address of the tuner, too. You don't show DIM, but I'm assuming it is more or less one of these two equivalent macros:
#define DIM(x) (sizeof(x)/sizeof(*(x)))
#define DIM(x) (sizeof(x)/sizeof((x)[0]))
On further analysis, your tuner structure contains a flexible array member. You can't sensibly allocate such variables as static or global variables, or as automatic variables; you have to allocate them with malloc() and relatives to get a non-empty array.
However, with that caveat in mind, this code compiles:
typedef enum Radio_types { C614L8 } Radio_types;
enum { tuned = 5 };
typedef struct tuner_s
{
char *device_name;
int frequency[tuned];
int power;
int dial_lamp;
int fd[];
} tuner;
typedef enum Lp_Sw_614L8 { OFF_loop, LEFT, RIGHT, SLEW_LEFT, SLEW_RIGHT } loopsw_614L8;
typedef enum Mo_Sw_614L8 { OFF_614L8, ADF, ANT, LOOP } modesw_614L8;
struct radio_s_614L8
{
loopsw_614L8 loop_sw_614L8;
modesw_614L8 mode_sw_614l8;
int sw_band;
int sw_bfo;
int meter;
tuner *Tuner;
int tuners;
};
static tuner tuner_614L8 = { .device_name = "/dev/TBD", };
static struct radio_s_614L8 radio_614L8 = { .Tuner = &tuner_614L8, .tuners = 1 };
struct rss_s
{
Radio_types device_type;
char *device_info;
char *device_model;
char *device_serial;
int power_48v;
int power_400hz;
int panel_lamps;
void *radio_info;
};
struct rss_s radios[] =
{
{ C614L8, "ADF", "614L8", "8384", 0, 0, 0, &radio_614L8, },
};

Resources