Possible to use the size of a struct to create an identifier? - c

Say I have a function which I want to call based on the size of a type.
Is there some way this can be done using a macro?
static int array_find_index_4_impl(void *array, const unsigned int arr_len, const void *var)
{
const int32_t *arr_step = arr;
unsigned int i;
for (i = 0; i < arr_len; i++, arr_step++) {
if (*arr_step == *(int32_t *)var) {
return (int)i;
}
}
return -1;
}
static int array_find_index_2_impl(void *array, const unsigned int arr_len, const void *var)
{
const int16_t *arr_step = arr;
unsigned int i;
for (i = 0; i < arr_len; i++, arr_step++) {
if (*arr_step == *(int16_t *)var) {
return (int)i;
}
}
return -1;
}
/* etc... for other sizes too */
#define array_find_index(array, array_len, var) \
array_find_index_##SOME_MAGIC_SIZEOF(*array)##_impl(array, array_len, var)
Possible solutions...
I know C11's _Generic can be used to check for specific types, but I was interested in ignoring the exact types and finding the right function based on size only.
Another option could be to store a lookup table of functions, eg:
#define array_find_index(array, var) \
array_find_index_fn_table[sizeof(*array)](array, var)
Which can work but would prefer to construct the identifier directly if possible.
Of course its possible to pass the sizeof to a function and use memcmp, but I'm interested to know if about creating identifiers from a structs size

Another possible solution could be to generate some X-macro header file with the size of the relevant types, i.e. to generate a file like
#define MY_SIZEOF_int 4
etc etc.... using some simple C generating file containing
#define WANT_SIZE(Typ) { \
printf("#define MY_SIZEOF_%s %d\n", \
#Typ, (int) sizeof(Typ)); };
and have somewhere
WANT_SIZE(int)
WANT_SIZE(my_struct_t)
and running the specialized generator in the build process...
assuming some typedef struct my_struct_st my_struct_t before (because this works only for simply named types).
Of course, this requires complexifying the building procedure (e.g. add a couple of rules and targets in your Makefile...)
Yet another solution could be to use (with GCC...) its __builtin_type_compatible_p or even customize it (by adding your specific pragmas or builtins) using MELT.

I have a function which I want to call based on the size of a type.
Is there some way this can be done using a macro?
Using only macros, no it can't be done. Macros are expended by the preprocessor, there is no awareness of an identifier's type at this stage, let alone its size.
In other words the preprocessor just doesn't have the information needed to do what you want.
However, a solution to the original problem of having a function called based on the size of a type could of course involve some preprocessing, like the one you proposed.

#include <stdio.h>
#include <string.h>
static int array_find_index(const void *array, const void *value, size_t numOfMember, size_t element_size){//option add compare function
size_t i;
const char *p = (const char *)array;
for(i = 0; i < numOfMember; ++i, p += element_size){
if(memcmp(p, value, element_size)==0)
return (int)i;
}
return -1;
}
#define ARRAY_FIND_INDEX(array, var) \
array_find_index(array, var, sizeof(array)/sizeof(*array), sizeof(*array))
int main (void){
int ia[] = {1,2,3,4,5};
int ikey = 3;
int index = ARRAY_FIND_INDEX(ia, &ikey);
printf("%d\n", index);
char ca[] = {'1','2','3','4','5'};
char ckey = '5';
index = ARRAY_FIND_INDEX(ca, &ckey);
printf("%d\n", index);
ckey = '0';
index = ARRAY_FIND_INDEX(ca, &ckey);
printf("%d\n", index);
return 0;
}

Related

Can I cast a variable to a type decided during execution in C

int* push_back_int(intVector* target, int push)
{
target->length++;
target->val = (int *)realloc(target->val, target->length * sizeof(int));
target->val[target->length - 1] = push;
return &target->val[target->length - 1];
}
float* push_back_float(floatVector* target, float push)
{
target->length++;
target->val = (float *)realloc(target->val, target->length * sizeof(float));
target->val[target->length - 1] = push;
return &target->val[target->length - 1];
}
Is there any way that I can hold a variable to replace the cast to int* or float* so that i can reuse the same code for multiple variable types using void*
No. In C the type is only available at compile-time.
You can use void * to pass data back and forth but you need to retain the element size. This approach is referred to as non-type safe (compiler will not catch the wrong "type", say, switching iq and fq below, which will then blow up most impressively at run-time when you get it wrong). Note how calling code handles the cast.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct queue {
size_t push_length;
void *val;
size_t length;
};
void *push_back(struct queue *target, void *push) {
size_t offset = target->length * target->push_length;
target->length++;
void *tmp = realloc(target->val, target->length * target->push_length);
if(!tmp) {
// error handling
return NULL;
}
target->val = tmp;
return memcpy((char *) target->val + offset, push, target->push_length);
}
int main() {
struct queue fq = { sizeof(float), NULL, 0 };
push_back(&fq, &(float) { 2.718 });
push_back(&fq, &(float) { 3.142 });
for(unsigned i = 0; i < fq.length; i++) {
printf("%u: %f\n", i, ((float *) fq.val)[i]);
}
struct queue iq = { sizeof(int), NULL, 0 };
push_back(&iq, &(int) { 1 });
push_back(&iq, &(int) { 2 });
for(unsigned i = 0; i < iq.length; i++) {
printf("%u: %d\n", i, ((int *) iq.val)[i]);
}
}
and the output:
0: 2.718000
1: 3.142000
0: 1
1: 2
Your platform may require specific alignment for each element of val (i.e. for type T push_length = sizeof(T) % alignof(T) ? (sizeof(T) / alignof(T) + 1) * alignof(T) : sizeof(T)).
Can I cast a variable to a type decided during execution (?)
Yes, in some cases that support variable length array.
(double (*)[r]) is a cast to a type determined at run time. Demonstrative code follows:
int r = rand();
double a[r];
double (*b)[r] = &a;
unsigned char *data = malloc(sizeof a);
b = data; // warning: assignment to 'double (*)[r]' from incompatible pointer type 'unsigned char *' [-Wincompatible-pointer-types]
b = (double (*)[r]) data; // OK
(void) b;
In OP's code, the cast nor the sizeof(type) are not needed.
Use target->val = realloc(target->val, target->length * sizeof(target->val[0])); for both.
Only difference remaining in push_back_...() is the function name and signature.
Is there any way that I can hold a variable to replace the cast to int* or float* so that i can reuse the same code for multiple variable types using void*.
Any object pointer can be held in a void *. Yet that void * does not certainly retain anything to denote the type from which it is assigned. Auxiliary data needed. In OP's case, the size of the type would be enough if the size was consistent per vector.
typedef struct {
size_t object_size;
size_t length;
void *val;
} gVector;
// Pass in the address of the object to push
void* push_back_g(gVector* target, const void *push) {
void *p = realloc(target->val, target->object_size * (target->length + 1u));
if (p) {
target->val = p;
return memcpy((unsigned char *)val + target->object_size * target->length++,
push, target->object_size);
}
// Handle error with TBD code
return NULL;
}
Alternative we could pass in the size per push call and store that too.
Yet in both cases, code loses type checking.
With _Generic, code could handle various pre-determined select types with common code. Yet it seems OP wants any type.
C does not have runtime type information (RTTI) so you would have to hack that out manually by introducing an enum or similar. However, I would not encourage type generic programming with enums + void pointers in modern C programming since it is type unsafe and clunky.
We could use macros to generate type-generic code based on a number of supported types, kind of like a poor man's version of C++ templates. But that creates code which is very hard to read and maintain, so it isn't advisable either. Just for the record, it might look like this:
// NOT RECOMMENDED PRACTICE
#define SUPPORTED_TYPES(X) \
X(int) \
X(float) \
#define vector_define(type) \
typedef struct \
{ \
type* val; \
size_t length; \
}type##Vector;
SUPPORTED_TYPES(vector_define)
#define push_back_define(type) \
type* push_back_##type (type##Vector* target, type push) \
{ \
target->length++; \
target->val = realloc(target->val, target->length * sizeof(type)); \
target->val[target->length - 1] = push; \
return &target->val[target->length - 1]; \
}
SUPPORTED_TYPES(push_back_define)
As you can see it starts to look like a different language and the code is pretty alien to read for anyone who isn't used at seeing "X-macros".
In this case the best solution is perhaps to write a version using void* but to wrap it in a type safe macros utilizing _Generic. Your vector could then be implemented as a single type-generic ADT. Not a separate one for int, float and so on. As for how to do that proper, it's too long an answer for SO - a place to start would be to read up on How to do private encapsulation in C?.
A simple example of how to use _Generic without creating a proper ADT:
#include <stdio.h>
void push_back_int (int* target, int push)
{ puts(__func__); }
void push_back_float (float* target, float push)
{ puts(__func__); }
#define push_back(arr,item) \
_Generic((arr), \
int*: push_back_int, \
float*: push_back_float) \
((arr), (item) )
int main (void)
{
int* i_arr;
int i_item = 5;
push_back(i_arr, i_item);
float* f_arr;
float f_item = 123.0f;
push_back(f_arr, f_item);
}

How to pass structure field name to function?

I have many similar function calls dealing with one structure, but each call is using different field of structure.
Example:
typedef struct {
int i1;
int i2;
int i3;
} S;
functions to get structure fields (it would be better to avoid them):
int getFieldI1 (S *s){ return s->i1; }
int getFieldI2 (S *s){ return s->i2; }
int getFieldI3 (S *s){ return s->i3; }
function i have to call many times:
void doJob (int (*get_field_func)(S *)){
//some code
S s;
int v = get_field_func(&s);
//some code
}
i call doJob() this way:
doJob(&getFieldI1);
doJob(&getFieldI2);
doJob(&getFieldI3);
i would like to do like this:
doJob(i1);
doJob(i2);
doJob(i3);
is it possible in C?
option 1 - offsets
You can use memory offsets.
void doJob (int offset){
//some code
S s;
int v = *(&s+offset*sizeof(int));
//some code
}
You can call it like this:
doJob(0);//i1
doJob(1);//i2
doJob(2);//i3
As pointed out in the comments, the offsets are unsafe. You can create a check for this:
if(offset>2||offset<0){
//some kind of error
}
Also, this can only be used if the structure only contains integers(or elements of the same type, you would need to adjust it)(see comments).
If there are elements before s1, s2 and s3, you'll need to add the size of the elements(as padding, just add it);
option 2 - constants
Another option (that hasn't the mentioned problems) is to define constants/macros:
You'll just define them like this:
#define I1 &getFieldI1
#define I2 &getFieldI2
#define I3 &getFieldI3
and just call it using:
doJob(I1);
doJob(I2);
doJob(I3);
Just pass in a pointer to the field:
void doJob( int* fieldPointer )
{
assert( fieldPointer != NULL );
// Get the field value:
int v = *fieldPointer;
// Do something with the field value:
v += 10;
// Save the updated value back to the field:
*fieldPointer = v;
}
Usage:
S structInstance = ...
doJob( &structInstance.i1 );
doJob( &structInstance.i2 );
doJob( &structInstance.i3 );
How to pass structure field name to function?
In general, you cannot. A typical library coded in C does not show fields of internal struct to outside. In other words, a field name is only known to the compiler, and relevant to the current translation unit, and makes no sense at runtime.
Consider the following metaprogramming approach: write a metaprogram (in C or in some scripting language like Guile, awk, Python, etc...) generating your C code, and set up your build accordingly. That might mean to edit your Makefile, or configure your build automation tool.
This is usual practice since the previous century. Look into SWIG or RPCGEN as a famous example.
You might perhaps use preprocessor tricks, e.g. X-macros.
Unfortunately, C doesn't allow exactly what you need. But you can achieve a partial win with some code changes.
I have one and half solutions. For the first I propose a (simplified!) implementation, for the second I provide just an hint. Please, check if they can be acceptable for you.
Your example structure:
typedef struct {
int i1;
int i2;
int i3;
} S;
I would define an enum representing the specific field:
typedef enum
{
FIELD_ID_I1,
FIELD_ID_I2,
FIELD_ID_I3,
FIELD_ID_MAX
} FieldId_e;
Then I would add a field parameter in your general function, managing internally the correct field to be returned. Some smart error managing in case of wrong ID has to be done here. I just return -1 for brevity.
int getField (S *s, FieldId id)
{
int ret = -1;
switch(id)
{
case FIELD_ID_I1:
ret = s->i1;
break;
case FIELD_ID_I2:
ret = s->i2;
break;
case FIELD_ID_I3:
ret = s->i3;
break;
}
return ret;
}
Your doJob will become
void doJob (int (*get_field_func)(S *, FieldId), FieldId id){
//some code
S s;
int v = get_field_func(&s, id);
//some code
}
And final call will become this one. But probably (and it depends on your scenario) having a single general function will make possible to omit the function pointer, simplifying much the interface.
doJob(&getField, FIELD_ID_I1);
doJob(&getField, FIELD_ID_I2);
doJob(&getField, FIELD_ID_I3);
Just a short reference to another tricky solution that would require to play with pointers.
Do you know offsetof macro? (Wikipedia EN)
It evaluates to the offset (in bytes) of a given member within a
struct or union type, an expression of type size_t. The offsetof()
macro takes two parameters, the first being a structure name, and the
second being the name of a member within the structure.
In this case you could have something like
int getField (S *s, size_t offset);
doJob(&getField, offsetof(S, i1));
I failed to guess right types for i1/i2/i3, sorry. So I use auto keyword from c++:
#include <stdio.h>
typedef struct {
int i1;
int i2;
int i3;
} S;
int getFieldI1 (S *s){ return s->i1; }
int getFieldI2 (S *s){ return s->i2; }
int getFieldI3 (S *s){ return s->i3; }
void doJob (int (*get_field_func)(S *)){
//some code
S s = {1,2,3};
//S s;
int v = get_field_func(&s);
//some code
printf("got: %d\n", v);
}
int main() {
S s = {1,2,3};
auto i1 = getFieldI1;
auto i2 = getFieldI2;
auto i3 = getFieldI3;
doJob(i1);
doJob(i2);
doJob(i3);
}
Then
g++ 59503102.cxx -o 59503102 && ./59503102
as expected produces
got: 1
got: 2
got: 3
plain c version
#include <stdio.h>
typedef struct {
int i1;
int i2;
int i3;
} S;
int getFieldI1 (S *s){ return s->i1; }
int getFieldI2 (S *s){ return s->i2; }
int getFieldI3 (S *s){ return s->i3; }
void doJob (int (*get_field_func)(S *)){
//some code
S s = {1,2,3};
//S s;
int v = get_field_func(&s);
//some code
printf("got: %d\n", v);
}
int main() {
S s = {1,2,3};
int (*i1)(S *) = getFieldI1;
int (*i2)(S *) = getFieldI2;
int (*i3)(S *) = getFieldI3;
doJob(i1);
doJob(i2);
doJob(i3);
}

Reducing code duplication in C program with nearly identical statements in if/else?

I am trying to reduce code duplication in my C program, where all the statements in each branch of an if/else block are identical, except for a function name and its arguments. The idea is that the user specifies either x, y, or z, and the program measures how long it takes to run either func_x, func_y, or func_z 1000 times.
More specifically, here is the high level design of the C code:
// struct definitions
struct dat_x {...};
struct dat_y {...};
struct dat_z {...};
// reading structs from a text file
struct dat_x read_dat_x_from_file(char *path);
struct dat_y read_dat_y_from_file(char *path);
struct dat_z read_dat_z_from_file(char *path);
// functions
int func_x(struct dat_x);
int func_y(struct dat_y);
int func_z(struct dat_z);
// runner computing runtime of func_x, func_y, or func_z
int main(int argc, char** argv) {
char *func_name = argv[1];
char *path = argv[2];
int a;
clock_t t;
if (strcmp(func_name, "x") == 0) {
struct dat_x args = read_dat_x_from_file(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_x(args);
}
t = clock() - t;
} else if (strcmp(func_name, "y") == 0) {
struct dat_y args = read_dat_y_from_file(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_y(args);
}
t = clock() - t;
} else if (strcmp(func_name, "z") == 0) {
struct dat_z args = read_dat_z_from_file(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_z(args);
}
t = clock() - t;
}
// report runtime
double e = ((double)t) / CLOCKS_PER_SEC;
printf("%s: %f %d\n", func_name, e, a);
}
As you can see, in the main function all the statements in each branch of the if-else block are identical; the only difference is that either func_x, func_y, or func_z.
In a functional language, this pattern can be abstract by having a function run_timing_benchmark which takes the func_* and dat_* arguments and hten runs the loop (possibly using polymorphism to define the signature of g). While I can use function pointers in C, I can't write a polymorphic type signature.
What are suggestions for how to reduce the duplication in this program so that the timing code is only defined once? In practice I may have dozens of functions (not just x/y/z) to benchmark using the same code, and the timing code may be more complex.
You can use a macro to generate the code. Since all the structures and functions follow a common naming scheme, you can use token pasting to generate them.
#define PROCESS(suffix, func_name_var, path_var, sum_var, time_var) \
time_var = time();
if(strcmp(func_name_var, #suffix) == 0) { \
struct dat_##suffix args = read_dat_##suffix##_from_file(path_var); \
for (int i = 0; i < 1000; i++) { \
sum_var += func_##suffix(args); \
} \
time_var = time() - time_var;
then you can use it like this:
PROCESS(x, func_name, path, a, t)
else PROCESS(y, func_name, path, a, t)
else PROCESS(z, func_name, path, a, t)
#MarcoBonelli observed correctly in comments that your functions are not quite as similar as they may seem. They have different argument and return types, which is an important distinction in strongly-typed languages such as C. Those functions are not interchangeable in a C-language sense; given that they have different return types, there's not even any function-pointer type that would be compatible with pointers to all the functions.
If you can change the functions then it would be possible to do so in a way that overcomes that limitation. For instance, you could accept the structures to populate as out parameters of type void *:
void read_dat_y_from_file(const char *path, void *args) {
struct dat_y *y_args = (struct dat_y *) args;
// ...
}
// ...
struct dat_y args;
read_dat_y_from_file(path, &args);
You could write a function-pointer-based solution around that.
But a simpler way forward that does not require modifying any functions would be to move the repeated code to a macro:
#define read_and_time(tag) do { \
struct dat_ ## tag args = read_dat_## tag ## _from_file(path); \
t = clock(); \
for (int i = 0; i < 1000; i++) { \
a += func_ ## tag(args); \
} \
t = clock() - t; \
while (0)
With that, you would reduce the if / else chain to
if (strcmp(func_name, "x") == 0) {
read_and_time(x);
} else if (strcmp(func_name, "y") == 0) {
read_and_time(y);
} else if (strcmp(func_name, "z") == 0) {
read_and_time(z);
}
You could even pull a bit more of that into the macro, but I think this form serves clarity best.
One idea could be to make a union to abstract the differences in function signatures and return values. Then build a table of functions and invoke the right one according to the name passed. Something like this: (warning: not tested!)
// struct definitions
struct dat_x {...};
struct dat_y {...};
struct dat_z {...};
// Build a union that contains the structs
union uargs
{
struct dat_x;
struct dat_y;
struct dat_z;
};
// reading structs from a text file (but packaged into the union type)
union uargs read_dat_x_from_file(char *path);
union uargs read_dat_y_from_file(char *path);
union uargs read_dat_z_from_file(char *path);
// functions
int func_x(union uargs dat);
int func_y(union uargs dat);
int func_z(union uargs dat);
struct table_t
{
char *name;
union uargs (*read_dat_fp);
int (*fp)(union uargs dat);
};
// Table of function pointers
struct table_t func_table[]
{
{ "x", read_dat_x_from_file, func_x},
{ "y", read_dat_y_from_file, func_y},
{ "z", read_dat_x_from_file, func_z}
};
// runner computing runtime of func_x, func_y, or func_z
int main(int argc, char** argv) {
char *func_name = argv[1];
char *path = argv[2];
int a;
clock_t t;
for(int i = 0; i < sizeof(func_table) / sizeof(table_t); i++)
{
if(strcmp(func_name, func_table[i].name) == 0)
{
union uargs args = func_table[i].read_dat_fp(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_table[i].fp(args);
}
t = clock() - t;
break;
}
}
// report runtime
double e = ((double)t) / CLOCKS_PER_SEC;
printf("%s: %f %d\n", func_name, e, a);
}
This gets rid of the code duplication and is also somewhat easily scalable.
Another option could be to use some macro magic as in this answer from #Barmar.
Edit: Of course, instead of the union, you could simply use void* and typecasting to pass along pointers to the structs, re-casting them as needed inside the functions. But then you completely throw away all type checking.
The best way would have been to give the functions the same interface. Then you could have created an array of function pointers and gotten quite pretty code.
However, if you are stuck with the functions as they are, the least evil way to reduce code repetition is to use function-like macros. For example by using C11 _Generic:
#define read_dat_from_file(result, path) (result) = \
_Generic((result), \
struct dat_x: read_dat_x_from_file, \
struct dat_y: read_dat_y_from_file, \
struct dat_z: read_dat_z_from_file ) (path);
Where result is a variable of the struct type that you want to store the results inside. Full example:
#include <stdio.h>
struct dat_x { int x; };
struct dat_y { int y; };
struct dat_z { int z; };
struct dat_x read_dat_x_from_file(char *path)
{
puts(__func__);
return (struct dat_x){1};
}
struct dat_y read_dat_y_from_file(char *path)
{
puts(__func__);
return (struct dat_y){2};
}
struct dat_z read_dat_z_from_file(char *path)
{
puts(__func__);
return (struct dat_z){3};
}
#define read_dat_from_file(result, path) (result) = \
_Generic((result), \
struct dat_x: read_dat_x_from_file, \
struct dat_y: read_dat_y_from_file, \
struct dat_z: read_dat_z_from_file ) (path);
int main (void)
{
struct dat_x x;
struct dat_y y;
struct dat_z z;
read_dat_from_file(x, "");
read_dat_from_file(y, "");
read_dat_from_file(z, "");
printf("%d\n", x.x);
printf("%d\n", y.y);
printf("%d\n", z.z);
}
Output:
read_dat_x_from_file
read_dat_y_from_file
read_dat_z_from_file
1
2
3
A not super elegant way, would be to use a function pointer like this:
int (*funcPtr)(void *arg)
And in the implementation of the function you cast the void * to the actual functions argument like struct dat_x *arg = (struct dat_x *)arg

Can't pass typedef struct to function by reference

I'm trying to pass a custom type object to a function by reference, and I can't figure out what I could be doing wrong. I read How do you pass a typedef struct to a function? as well as other references and could swear I'm already doing exactly that. I cleared out everything else I'm doing and even this spartan code throws 5 errors. Help me, Stackexchange; You're my only hope!
The goal is simply to be able to alter the values in the array in the object.
#include <stdio.h>
#include <math.h>
typedef struct structure {
char byte[10];
char mod;
} complex;
void simpleInit (complex *a, char value) {//put the value in the first byte and zero the rest
a.byte[0] = value;
char i;
for (i = 1; i < 10; ++i) {
a.byte[i] = 0;
}
a.mod = 1;
}
void main () {
complex myNumber;
char value = 6;
simpleInit (myNumber, value);
}
When I attempt to run this I get this error and 4 similar:
test2.c:10:3: error: request for member ‘byte’ in something not a structure or union
a.byte[0] = value;
a is a pointer type, so you need to de-reference it to use it. Typically that's done with the arrow operator:
a->byte[i] = 0;
Since this is just an array of bytes you can also quickly "zero" it:
memset(a, 0, 10);
Though given how important 10 is in your code you should codify that in a constant or a #define.
When you pass a value by reference you need to use asterisk to access al fields of the structure, for example:
(*a).byte[0] = value;
Happily you have -> as a shortcut, so this will be:
a->byte[0] = value;
Also do not forget to call the & (address of) operator when you call simpleInit.
#include <stdio.h>
#include <math.h>
typedef struct structure
{
char byte[10];
char mod;
} complex;
void simpleInit (complex *a, char value)
{
char i;
a->byte[0] = value;
for (i = 1; i < 10; ++i) {
a->byte[i] = 0;
}
a->mod = 1;
}
int main()
{
complex myNumber;
char value = 6;
simpleInit (&myNumber, value);
}

How to access members of a `struct' according to a variable integer in C?

Suppose I have this struct (which incidentally contain bit-fields, but you shouldn't care):
struct Element {
unsigned int a1 : 1;
unsigned int a2 : 1;
...
unsigned int an : 1;
};
and I want to access the i'th member in a convenient way. Let's examine a retrieval solution.
I came up with this function:
int getval(struct Element *ep, int n)
{
int val;
switch(n) {
case 1: val = ep->a1; break;
case 2: val = ep->a2; break;
...
case n: val = ep->an; break;
}
return val;
}
But I suspect that there is a much simpler solution. Something like array accessing style, maybe.
I tried to do something like that:
#define getval(s,n) s.a##n
But expectedly it doesn't work.
Is there a nicer solution?
Unless you have specific knowledge of the underlying structure of the struct, there is no way to implement such a method in C. There are all sorts of problems that will get in the way including
Members of different sizes
Packing issues
Alignment issues
Tricks like bitfields will be problematic
You're best off implementing a method by hand for your struct which has a deep understanding of the internal members of the structure.
If every field in your struct is an int, then you should basically be able to say
int getval(struct Element *ep, int n)
{
return *(((int*)ep) + n);
}
This casts the pointer to your struct to a pointer to an array if integers, then accesses the nth element of that array. Since everything in your struct seems to be an integer, this is perfectly valid. Note that this will fail horribly if you ever have a non-int member.
A more general solution would be to maintain an array of field offsets:
int offsets[3];
void initOffsets()
{
struct Element e;
offsets[0] = (int)&e.x - (int)&e;
offsets[1] = (int)&e.y - (int)&e;
offsets[2] = (int)&e.z - (int)&e;
}
int getval(struct Element *ep, int n)
{
return *((int*)((int)ep+offsets[n]));
}
This will work in the sense that you'll be able to call getval for any of the int fields of your struct, even if you have other non-int fields in your struct, since the offsets will all be correct. However, if you tried to call getval on one of the non-int fields it would return a completely wrong value.
Of course, you could write a different function for each data type, e.g.
double getDoubleVal(struct Element *ep, int n)
{
return *((double*)((int)ep+offsets[n]));
}
and then just call the proper function for whichever datatype you'd want. Incidentally, if you were using C++ you could say something like
template<typename T>
T getval(struct Element *ep, int n)
{
return *((T*)((int)ep+offsets[n]));
}
and then it would work for whatever datatype you'd want.
If your struct was anything except bitfields, you could just use array access, if I'm right in remembering that C guarantees that a series of members of a struct all of the same type, has the same layout as an array. If you know which bits in what order your compiler stores bitfields into integer types, then you could use shift/mask ops, but that's then implementation-dependent.
If you want to access bits by variable index, then it's probably best to replace your bitfields with an integer containing flag bits. Access by variable really isn't what bitfields are for: a1 ... an are basically independent members, not an array of bits.
You could do something like this:
struct Element {
unsigned int a1 : 1;
unsigned int a2 : 1;
...
unsigned int an : 1;
};
typedef unsigned int (*get_fn)(const struct Element*);
#define DEFINE_GETTER(ARG) \
unsigned int getter_##ARG (const struct Element *ep) { \
return ep-> a##ARG ; \
}
DEFINE_GETTER(1);
DEFINE_GETTER(2);
...
DEFINE_GETTER(N);
get_fn jump_table[n] = { getter_1, getter_2, ... getter_n};
int getval(struct Element *ep, int n) {
return jump_table[n-1](ep);
}
And some of the repetition could be avoided by the trick where you include the same header multiple times, each time having defined a macro differently. The header expands that macro once for each 1 ... N.
But I'm not convinced it's worth it.
It does deal with JaredPar's point that you're in trouble if your struct mixes different types - here all the members accessed via a particular jump table must of course be of the same type, but they can have any old rubbish in between them. That still leaves the rest of JaredPar's points, though, and this is a lot of code bloat for really no benefit compared with the switch.
No, there is no simple way to do this easier. Especially for bitfields, that are hard to access indirectly through pointers (you cannot take the address of a bitfield).
You can of course simplify that function to something like this:
int getval(const struct Element *ep, int n)
{
switch(n)
{
case 1: return ep->a1;
case 2: return ep->a2;
/* And so on ... */
}
return -1; /* Indicates illegal field index. */
}
And it seems obvious how the implementation can be further simplified by using a preprocessor macro that expands to the case-line, but that's just sugar.
If the structure really is as simple as described, you might use a union with an array (or a cast to an array) and some bit-access magic (as in How do you set, clear and toggle a single bit in C?).
As Jared says, the general case is hard.
I think your real solution is to not use bitfields in your struct, but instead define either a set type or a bit array.
I suggest code generation. If your structures don't contain huge amount of fields you can auto generate routines for each field or for a range of fields
and use them like:
val = getfield_aN( myobject, n );
or
val = getfield_foo( myobject );
If you have
Only bitfields, or all the bitfields first in your struct
less than 32 (or 64) bitfields
then this solution is for you.
#include <stdio.h>
#include <stdint.h>
struct Element {
unsigned int a1 : 1;
unsigned int a2 : 1;
unsigned int a3 : 1;
unsigned int a4 : 1;
};
#define ELEMENT_COUNT 4 /* the number of bit fields in the struct */
/* returns the bit at position N, or -1 on error (n out of bounds) */
int getval(struct Element* ep, int n)
{
if(n > ELEMENT_COUNT || n < 1)
return -1;
/* this union makes it possible to access bit fields at the beginning of
the struct Element as if they were a number.
*/
union {
struct Element el;
uint32_t bits;
} comb;
comb.el = *ep;
/* check if nth bit is set */
if(comb.bits & (1<<(n-1))) {
return 1;
} else {
return 0;
}
}
int main(int argc, char** argv)
{
int i;
struct Element el;
el.a1 = 0;
el.a2 = 1;
el.a3 = 1;
el.a4 = 0;
for(i = 1; i <= ELEMENT_COUNT; ++i) {
printf("el.a%d = %d\n", i, getval(&el, i));
}
printf("el.a%d = %d\n", 8, getval(&el, 8));
return 0;
}
Based on eli-courtwright solution but without using array of field offsets
......
if you have a structure containing pointer field like this, maybe you could write:
struct int_pointers
{
int *ptr1;
int *ptr2;
long *ptr3;
double *ptr4;
std::string * strDescrPtr;
};
Then you know that every pointer has a 4 bytes offset from a pointer to the structure, so you can write:
struct int_pointers ptrs;
int i1 = 154;
int i2 = -97;
long i3 = 100000;
double i4 = (double)i1/i2;
std::string strDescr = "sample-string";
ptrs.ptr1 = &i1;
ptrs.ptr2 = &i2;
ptrs.ptr3 = &i3;
ptrs.ptr4 = &i4;
ptrs.strDescrPtr = &strDescr;
then, for example, for a int value you can write:
int GetIntVal (struct int_pointers *ep, int intByteOffset)
{
int * intValuePtr = (int *)(*(int*)((int)ep + intByteOffset));
return *intValuePtr;
}
Calling it by:
int intResult = GetIntVal(&ptrs,0) //to retrieve the first int value in ptrs structure variable
int intResult = GetIntVal(&ptrs,4) //to retrieve the second int value in ptrs structure variable
and so on for the others structure fields values (writing other specific functions and using correct bytes offset value (multiple of 4)).
Although the OP specifies that we shouldn't care about the contents of the struct, since they are just bitfields would it be possible to use a char or int (or whatever data type has the size required) to create an n-bit "array" in this case?
void writebit(char *array, int n)
{
char mask = (1 << n);
*array = *array & mask;
}
with the char types replaced with a larger type if a longer "array" was needed. Not sure this is a definitive solution in other structs but it should work here, with a similar readbit funcition.
If you want to access your structure using both element index:
int getval(struct Element *ep, int n)
and by name:
ep->a1
then you are stuck with some hard to maintain switch like method that everyone has suggested.
If, however, all you want to do is access by index and never by name, then you can be a bit more creative.
First off, define a field type:
typedef struct _FieldType
{
int size_in_bits;
} FieldType;
and then create a structure definition:
FieldType structure_def [] = { {1}, {1}, {1}, {4}, {1}, {0} };
The above defines a structure with five elements of size 1, 1, 1, 4 and 1 bits. The final {0} marks the end of the definition.
Now create an element type:
typedef struct _Element
{
FieldType *fields;
} Element;
To create an instance of an Element:
Element *CreateElement (FieldType *field_defs)
{
/* calculate number of bits defined by field_defs */
int size = ?;
/* allocate memory */
Element *element = malloc (sizeof (Element) + (size + 7) / 8); /* replace 7 and 8 with bits per char */
element->fields = field_defs;
return element;
}
And then to access an element:
int GetValue (Element *element, int field)
{
/* get number of bits in fields 0..(field - 1) */
int bit_offset = ?;
/* get char offset */
int byte_offset = sizeof (Element) + bit_offset / 8;
/* get pointer to byte containing start of data */
char *ptr = ((char *) element) + byte_offset;
/* extract bits of interest */
int value = ?;
return value;
}
Setting values is similar to getting values, only the final part needs changing.
You can enhance the above by extending the FieldType structure to include information about the type of value stored: char, int, float, etc, and then write accessors for each type which checks the required type against the defined type.
Why not build getval() in to the struct?
struct Whang {
int a1;
int a2;
int getIth(int i) {
int rval;
switch (i) {
case 1: rval = a1; break;
case 2: rval = a2; break;
default : rval = -1; break;
}
return rval;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Whang w;
w.a1 = 1;
w.a2 = 200;
int r = w.getIth(1);
r = w.getIth(2);
return 0;
}
getIth() would have knowledge of the internals of Whang, and could deal with whatever it contained.

Resources