Declare struct and struct-size related arrays - c

I'm working in a condition like this:
typedef struct __type_x{
sub_type_a a;
sub_type_b b;
sub_type_c c;
}type_x_t;
uint32_t type_x_uids[] = {
1, //a's_uid
2, //b's_uid
3, //c's_uid
};
uint32_t type_x_uid_another[] = {
3, //a's uid in another API system
1, //b's uid in another API system
2, //c's uid in another API system
};
uint32_t type_x_uids_one_more[] = {
1, //a's_uid in yet another system
3, //b's_uid in yet another system
2, //c's_uid in yet another system
};
The problem is: If I need to add one more data(like d) into struct type_x_t, I need to add its uids into all other three arrays.
It is hard to maintain the code.
So I'm wondering if it is possible to maintain all these data from four places into one table?
I can put three uint32 arrays into one 2D array
uint32_t uid[system_id][value];
but I also have to maintain two pieces of code instead of one.
I'm wondering if there is anyway I can move forward? Therefore I can maintain one table to manage all these data. Such like
{#data_type, #data_name, #uid_1, #uid2, #uid 3},
Trying to use Macro to solve the problem, but I cannot access the data in certain position by __VA_ARGS__.

First of all, if you have placed the code adjacently in one single file, you are actually maintaining one place and not several. What you have is not necessarily bad. Anyway...
I will assume there's a reason why type_x_t is a struct and not an array. Then clearly the best design is to add the "uid" for "a" to the sub_type_a struct, or alternatively make a new struct containing both, since those data belong together.
If that's not an option, you could go with the array and then put that inside the type_x_t struct.
If that's not an option either, consider some completely different program design.
With all program design options exhausted, then - and only then - you could consider macros. What you are fishing for is so-called "X macros", which is the last resort and not really recommended, since they make the code much harder to read. The purpose of X macros is to centralize code maintenance of data to one place. It goes like this:
#include <stdint.h>
#define TYPE_X_LIST \
X(a,1,3,1) \
X(b,2,1,3) \
X(c,3,2,2)
typedef struct
{
#define X(name, dummmy1, dummy2, dummy3) sub_type_##name name;
TYPE_X_LIST
#undef X
} type_x_t;
uint32_t type_x_uids[] = {
#define X(dummy1, id, dummy2, dummy3) id,
TYPE_X_LIST
#undef X
};
uint32_t type_x_uid_another[] = {
#define X(dummy1, dummy2, id, dummy3) id,
TYPE_X_LIST
#undef X
};
uint32_t type_x_uids_one_more[] = {
#define X(dummy1, dummy2, dummy3, id) id,
TYPE_X_LIST
#undef X
};
Now you only have to change the "TYPE_X_LIST" when you need to change the data. If you want to keep track of how many data sets you have, you can add an enum to count them:
typedef enum
{
#define X(name, ...) something_##name,
TYPE_X_LIST
#undef X
TYPE_X_N // the number of data sets
} type_x_size_t;
Then TYPE_X_N could be used to set array sizes etc.

Related

Dynamic method of calling structures in C

I have a project which involves writing a C program for some software used by my company. I want it to be as efficient as possible, but the way the software references the signals I'm working with is a little wonky. I'm working with 4 sets of 96 signals; these signals are grouped into 32 groups with 3 members each. Rather than generic functions to work with these signals (the generic functions exist, but there's no documentation on how they work), the auto-generated header file has defined a group of macros (I think) for each of these groups.
Each of the groups are defined as follows...
typedef struct {
//struct members
} AB_A_Group_A_Network
Each of those structures have a group of macros(?) defined like this...
void AB_A_Group_ZF_Network_Init(AB_A_Group_A_Network *pAbc)
{
double values[6]
...
pAbc->Member_1 = values[3] //array positions vary
pAbc->Member_2 = values[4]
pAbc->Member_3 = values[5]
}
The software's tech support suggested I do the following, but I was hoping there'd be a better way to do it. Of course this is a long method, but I can write it with a python script no problem, if need be. These 250+ lines of code will run every second in my application for each data set.
AB_A_Group_A_Network GroupA;
AB_A_Group_B_Network GroupB;
//...and so on
AB_A_Group_ZF_Network GroupZF;
AB_A_Group_A_Network_Init(&GroupA);
AB_A_Group_B_Network_Init(&GroupB);
//...and so on
AB_A_Group_ZF_Network_Init(&GroupZF);
CD_Array_Set(0,GroupA.Member_1); //a custom array function meant to interface with the software
CD_Array_Set(1,GroupA.Member_2);
//...and so on
CD_Array_Set(95,GroupZF.Member_96);
//...Repeat 3 times for 4 sets of data (Data sets A-D), with checks to see if that data exists
I thought of doing something like this, but I'm not sure you can use char arrays in this way. I'll add the disclaimer don't have much experience with C, so this might look/sound really stupid. This isn't working code, just a stream of consciousness. I'm also not sure if doing it in this way, if possible, would just end up losing efficiency. I'm completely open to other methods.
char groupName[70] = "AB_*_Group_*_Network";
char dataset = 'A';
char group = 'A';
char member = '1';
char groupInit[70]
//write a loop to increment dataset alphabetically
//check if dataset exists
groupName[3] = dataset;
//write a sub-loop to increment group alphabetically (each set has 32 groups)
groupName[27] = group;
//use groupName in place of struct name (not sure how or if this is possible with my current methods)
groupInit = strncat(groupName, "_Init", 5);
//use groupInit in place of _init macro name
//write a sub-loop to increment member numerically (each group has 3 members)
char member[10] = "Member_*";
member[7] = member;
CD_Array_Set(i,groupName.member);
Is the long method really the best way of doing this? Any advice you can offer is appreciated!
There's no way to refer to variables and type names dynamically from strings at runtime. But you can use token pasting in a macro to avoid all the repeated code.
#define INIT_GROUP(dataset, group) \
AB_ ## dataset ## _Group_ ## group ## _Network Group ## group; \
AB_ ## dataset ## _Group_ ## group ## _Network_Init(&Group ## group); \
CD_Array_Set(0,Group ## group .Member_1); \
CD_Array_Set(1,Group ## group .Member_2); \
...
CD_Array_Set(95,Group ## group .Member_96);
Unfortunately, there are no loops in the preprocessor, so you have to write all 96 CD_Array_Set lines in the macro.
With this macro, you can then write:
INIT_GROUP(A, A)
INIT_GROUP(A, B)
...
INIT_GROUP(A, ZF)
Auto generated C code
It is possible to do such things in C but it requires ugly Macros.
First thing i would look at is
An old Stackoverflow question: https://stackoverflow.com/a/12591965/8964221
And the mentioned gist in it: https://gist.github.com/epatel/3786323
BUT!
I would think about the time it would consume to have it bug free and working.
It won`t be that easy to transform it to ur needs.

Accessing enum strings by array notation?

If I were to compare these enum values in a switch statement. What is the purpose of numbering the strings?
If I store the enum in a header file and then import the header file. I know that I can say events event = ls; (I can store ls into events)
But can I say something like event[0] to access ls?
#define NUM_EVENTS 11
typedef enum events {
ls = 0,
rs = 1,
ws = 2,
lo = 3,
ro = 4,
lc = 5,
rc = 6,
gru = 7,
grl = 8,
gll = 9,
glu = 10
} events;
There's no such thing as enum strings. What you're talking about are identifiers, only used in the source code. An enum in C is represented as an integer type, typically int, but compilers are free to chose e.g. short or another one. An enum is even allowed to hold a value that doesn't correspond to one of the named members. Only these numbers go in the compiled programs. C compilers do not (have to) store any type information in the compiled executable.
So, if you need the enum identifiers as strings at runtime, you have to store them yourself. This typically looks like e.g.
typedef enum events {
ls,
rs,
ws,
lo,
ro,
lc,
rc,
gru,
grl,
gll,
glu
} events;
static const char *event_names[] = {
"ls",
"rs",
"ws",
"lo",
"ro",
"lc",
"rc",
"gru",
"grl",
"gll",
"glu"
};
void example(event ev)
{
// might want to check for a valid value here ...
// print name of event
puts(event_names[ev]);
}
As a side note, there's no need to explicitly number the members in your case -- the default numbering starts at 0 and increases by one for each member.
Further hints:
enum member identifiers are global, so it's a good practice to make them unique, e.g. by prepending the type name like this:
typedef enum events {
event_ls,
event_rs,
// ...
} events;
The above code violates the DRY (don't repeat yourself) principle: when changing the enum, you have to touch two different locations in the code which is a source of potential bugs. This is sometimes solved using X macros. There are opposing opinions whether this is good or bad style, just presenting it here for completeness:
#define EVENTS_LIST \
X(ls) \
X(rs) \
X(ws) \
X(lo) \
X(ro) \
X(lc) \
X(rc) \
X(gru) \
X(grl) \
X(gll) \
X(glu)
#define X(name) event_##name ,
typedef enum events {
EVENTS_LIST
} events;
#undef X
#define X(name) #name ,
static const char *event_names[] = {
EVENTS_LIST
};
#undef X
after preprocessing, this produces
typedef enum events {
event_ls , event_rs , event_ws , event_lo , event_ro , event_lc , event_rc , event_gru , event_grl , event_gll , event_glu ,
} events;
static const char *event_names[] = {
"ls" , "rs" , "ws" , "lo" , "ro" , "lc" , "rc" , "gru" , "grl" , "gll" , "glu" ,
};
You can cast from an integer to an enum, which is equivalent to indexing if the enum is a dense sequence starting at zero. In general enums are just a way to introduce symbolic names for a list of related constants. It is syntactically better than doing so using #define but there is very little functionality beyond such. If the numbers are not explicitly assigned, the compiler will manage assigning unique values to each member. But even finding the max value is not something offered by the language, much less mapping to names as strings or similar.
I think you are asking how to get the name of the event as a string from the event so you can do something like printf("%s\n", SOMEFUNCTION(event)); to print the name of the event.
There's is no such function.
If you really want to use event[0] you can do this:
events event[11];
event[0] = ls;
event[1] = rs;
event[2] = ws;
event[3] = lo;
event[4] = ro;
event[5] = lc;
event[6] = rc;
event[7] = gru;
event[8] = grl;
event[9] = gll;
event[10] = glu;
I will say though, I am sure there is a way around doing this ( since it is not elegant at all ), if you give more context :)
EDIT: After re-reading your question, I get the impression you want the STRING "ls" from your enum?
If this is so, then no you are not able to do this. Enumerated types are great for switch statements, but if you are trying to turn a variable name into a string through code without hardcoding event[0] = "ls", it isn't going to happen.

C89 computed goto (again) how to

I need to code an automata, and I bumped into this old need of a computed goto (ala fortran4 :) )
I need to code this in a portable ansi-C.
I want to stay away from the "don't do that", away from longjmp/setjmp, away from embedded ASM(), away from non ansi-C extensions.
Does anyone know how to do this?
Like I said in a comment, despite your plea to not use anything other than goto, standard C has nothing to offer.
Design your state appropriately, and pass a pointer to it to the handler functions for them to modify. That way the handler can setup the next function to call. Something like this:
struct state;
typedef void state_func(struct state*);
#define NULL_ACTION_ADDRESS (state_func*)0
struct state {
state_func *action;
int value1;
int value2;
};
#define INIT_STATE { initial_action, -1, -1}
state_func initial_action;
state_func handle_a;
state_func handle_b;
int main(void) {
struct state s = INIT_STATE;
while(s.action != NULL_ACTION_ADDRESS) {
(*s.action)(&s);
}
return 0;
}
void initial_action(struct state* ps) {
ps->action = &handle_a;
}
void handle_a(struct state* ps) {
ps->action = &handle_b;
}
void handle_b(struct state* ps) {
ps->action = NULL_ACTION_ADDRESS;
}
I think I got it, I reviewed all the various threads on this topics and I started to agree that that there where no ansi C solutions, yet I found an way to do this that fit my needs. All solution I saw on stackoverflow where based on the idea to 'get' the addr of a label, then stuff it into a table, then index this table and goto, this is both with gcc/clang non ansi extension or the asm extension.
I gave it another try tonite and got this.
In an include file named cgoto.h I have this
#ifndef CGOTO_dcl
#define CGOTO_dcl(N) int CGOTO_##N
#define CGOTO_LE(l) l,
#define CGOTO_LG(l) case l:goto l;
#define CGOTO_def(N) \
if(0){typedef enum {N(CGOTO_LE)} N; CGOTO_##N: switch(CGOTO_##N)\
{N(CGOTO_LG) default:CGOTO_##N=0;goto CGOTO_##N;}}
#define CGOTO(N,i) CGOTO_##N=i; goto CGOTO_##N;
#endif
The usage is like this
#include <stdio.h>
#include "cgoto.h"
int f(int x)
{ //...
CGOTO_dcl(gtb);
//...
# define gtb(L) L(l0) L(l1) L(l2)
CGOTO_def(gtb);
//...
CGOTO(gtb,x);
l0: printf("error\n");
return(0);
//...
l1:return(11);
l2:return(22);
l3:return(33);
}
int main()
{ printf("f(0)=%d f(1)=%d f(2)=%d,f(3)=%d\n",f(0),f(1),f(2),f(3));
}
In this implementation, the cost of jumping is 2 jumps and a switch() that is sequential, then optimisable. So this is reasonably performing compared to function call, a little less performing than &&label solution at the cost of portability.
With this implementation, labels code (semantic actions) are not confined into a switch() so we can implement jump table with shared semantic actions.
The index is assigned to a local goto_table_index, making the function using this re-entrant (multi threadable), though the optimiser can remove altogether this temp assignment.
The 1st Label in a jump table is 'special' (on this implementation) in the sense that it catch index out of bound, the first label is the 'error' label. If your code is bullet proof, i.e there is no way you can get an out of bound index, then the 1st label has not particular semantic.
CGOTO_dcl(gtb);
Declare the jump table 'gtb' own index as an auto integer so reentrant.
# define gtb(L) L(l0) L(l1) L(l2)
CGOTO_def(gtb);
Define a jump table named gtb, labels can be entered/removed with L(label) so it is pretty convenient, and this is symbolic by nature, i.e the labels are name with a meaning. With #define as a switch() case, labels addition/suppression often mean #define renumbering that is a problem.
The #define can be separated from the CGOTO_def() but it make more sense to keep them together. The CGOTO_def() though got to be placed after the function local declaration as it contain a switch() that is code.
A uniq jump table can be used in multiple place in the function.
CGOTO(gtb,x);
...
CGOTO(gtb,y);
A label may be entered in multiple jump table
# define gtb1(L) L(l0) L(l1) L(l2)
CGOTO_def(gtb1);
# define gtb2(L) L(l0) L(l4) L(l5)
CGOTO_def(gtb2);
So all in all, this may looks ugly, yet, the jump table definition though 2 line the #define and the CGOTO_def() is manageable and practical, semi performant, and portable.
We are back to FTN4 :)
Cheers,
Phi

Could I use preprocessor to make this one clearer?

I was writing a little source file function for my Pic32 and I got stucked on one thing.
It's basically an utility that should store incomming char data into buffer and then, if '\r' is recieved, it compares the buffer against list of commands (in array names), and if match is found, the index of the item is returned.
This part is from header:
#define NAMECNT 6
static const char names[NAMESCNT][10] = { // 6commands, max 10 char each
"korr", // 1
"adc", // 2
"fft", // 3
"data", // 4
"pr", // 5
"prsc"}; // 6
/* functions */
extern int comm(char cdata);
At the main file, there is one big switch:
switch( comm(recieved_ch) ){
case 1: foo1(); break;
case 2: foo2(); break;
...
}
Now, for the better clarity, I wanted to use instead of 1, 2, ... the original names (like case KORR: case ADC:) so I wrote deffinitions for each one of them
#define KORR 1
#define ADC 2
But I don't like that solution, because I want to use this source file in more projects and there is gonna be different list of commands for each. Is there any way how to do this?
Best thing would be to create the array names in preprocessor, but I doubt that's even possible. I was thinking about using enum type (which would have same items as list of commands names), but I am not sure how would that go.
You can use X-macros to build an enum and fill the array, then you can use the enum values in the switch:
#define VARS \
X(korr) \
X(adc) \
X(fft) \
X(data) \
X(pr) \
X(prsc)
static const char names[][10] = { // 6commands, max 10 char each
#define X(name) #name,
VARS
#undef X
};
enum evars {
#define X(name) name,
VARS
#undef X
};
extern int comm(char cdata);
int main(void)
{
char x = 1;
switch (comm(x)) {
case korr:
printf("korr");
break;
case adc:
printf("adc");
break;
/* ... and so on */
}
return 0;
}
The expansion of X is:
static const char names[][10] = {
"korr", "adc", "fft", "data", "pr", "prsc",
};
enum evars {
korr, adc, fft, data, pr, prsc,
};
Edit: As pointed out by #5gon12eder, you don't need to hardcode 6 in the first dimension of the array (you can leave it unspecified).
The preprocessor could make things clearer here, I think, using the concatentation operator ##, but it'll not yield a performance advantage. A switch statement could be optimized by the compiler, but that's implementation-dependent.
Instead of the "one big switch," use an array of function pointers. Something like
func_ptrs[comm(received_ch) - 1]();
will call the corresponding function, where foo1 is at index 0, foo2 at 1, etc. To add a command, simply append a command name to the command list and a function pointer func_ptrs.
After all, you kill two birds with one stone: you create an easy way to add commands and improve performance.
Besides, a linear search through an array of strings is pretty inefficient. A hash table would yield a performance advantage.

Static mapping of array index and array content in C

I am having a list of parameters. Each parameter is defined by an unique identifier (ParamID) and some other data (&ParamX, SomeOtherDataX) associated with this parameter. All the available parameters are organized in a table, which is implemented as a struct array (ParameterList[]) in C. Thus, on each row I can see all associated data for one parameter. The following code snippet should (hopefully) make this clearer:
// predefined IDs; not changeable!
#define PARAM_ID_A 10
#define PARAM_ID_B 12
#define PARAM_ID_C 14
// the basic structure of my parameter list
typedef struct ParameterList_t {
int ParamID,
*int ParamAddr,
*float SomeConnectedData
}
// definition of my list in ROM
const ParameterList_t ParameterList[] = {
{ PARAM_ID_A, &Param1, SomeOtherData1},
{ PARAM_ID_B, &Param2, SomeOtherData2},
{ PARAM_ID_C, &Param3, SomeOtherData3}
};
Now I want to create another list, which contains references on a subset of the parameters defined in the ParameterList[] table. This list should also be resided in ROM. I basically want to access all associated data for a subset of the parameters.
const *ParameterList_t ParameterSubListA[] = {
&ParameterList[2], // parameter: PARAM_ID_B
&ParameterList[3], // parameter: PARAM_ID_C
};
The problem here is that the code will be maintained by many people and the parameter list (ParameterList[]) might change frequently and parameters will be sorted into the table at the beginning or in the middle. This means the sub list (ParameterSubListA[]) must be updated to point to the desired parameters if their index (index = row in ParameterList[]) changes.
Question:
Basically my code needs a mapping from ParamID to the index of the ParameterList[] table, preferably by use of the preprocessor and only in ROM. I found different ways to implement this, which are all not satisfying:
Option 1:
Automatically generate a list in the RAM at startup, which maps the ParamID to the index in ParameterList[]. What I get is an array, that could be called CrossRefTable[]:
IndexOfParameterA_InParameterList = CrossRefTable[PARAM_ID_A];
My sublist would then look like this (cannot be constant anymore :/ ):
*ParameterList_t ParameterSubListA[] = {
&ParameterList[CrossRefTable[PARAM_ID_B]], // parameter: PARAM_ID_B
&ParameterList[CrossRefTable[PARAM_ID_C]], // parameter: PARAM_ID_C
};
I am short of RAM, so I would prefer a solution that only uses ROM.
Option 2:
Use a predefined macro __COUNTER__, which increments with each call and generate a macro in each row:
const ParameterList_t ParameterList[] = {
{ PARAM_ID_A, &Param1, SomeOtherData1},
#define PARAM_IDX_A __COUNTER__
{ PARAM_ID_B, &Param2, SomeOtherData2},
#define PARAM_IDX_B __COUNTER__
{ PARAM_ID_C, &Param3, SomeOtherData3}
#define PARAM_IDX_C __COUNTER__
};
My sublist would then look like this:
const *ParameterList_t ParameterSubListA[] = {
&ParameterList[PARAM_IDX_B], // parameter: PARAM_ID_B
&ParameterList[PARAM_IDX_C], // parameter: PARAM_ID_C
};
I would favorise this option, apparently it is not possible to use GCC.
Other Options:
I also figured there might be a possiblity in using X-MACROS, but I am not sure about that.
Boost is also not an option.
Hopefully my explanation is somehow clear...
Since the data is static, I'd say go on and initialize it statically.
Using external tools if the compiler is not capable enough.
parameter_list.c:
const struct ParameterList_t ParameterList[] = {
{ PARAM_ID_A, &Param1, SomeOtherData1},
{ PARAM_ID_C, &Param2, SomeOtherData2},
{ PARAM_ID_B, &Param3, SomeOtherData3}
};
#include "parameter_list_index.h"
const *ParameterList_t ParameterSubListA[] = {
&ParameterList[PARAM_ID_C_INDEX],
&ParameterList[PARAM_ID_B_INDEX],
};
parameter_list.px:
#!/usr/bin/perl -n
print "#define $1_INDEX ".($n++)."\n" if
/^const.*ParameterList\[\]/../^}/ and /^\s*{\s*([^,]+)/;
Makefile:
parameter_list.o: parameter_list.c parameter_list.h
parameter_list_index.h: parameter_list.c
./parameter_list.px $< > $#
This is just a general idea, your implementation may differ of course.
You may choose to generate ParameterList[] the same way or use [PARAM_ID_A_INDEX] = { ... } to make extra sure the indexes match.
Note the code above relies heavily on formatting, which may or may not be ok.
And in any case, some people may find tricks like this inappropriate.
Were I doing this, and I needed flexibility
Then I would have defined an enum that matches the table of data.
(no actual instance of the enum needed, just the definition
Then declared an array that contains some values from the enum.
The values in that array are the offsets into the data array

Resources