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);
}
Related
I have a c struct that has a const variable.
typedef struct {
u32 status;
const u32 dir_search_idx;} FS_OBJ;
What I would like to do is init the const variable in a function once I have created the struct object. I guess I want to do something similar to what a constructor would do in c++. Is it possible to do something similar in c? Thanks
This should work perfectly fine if you are using C99 or newer and want to initialize the const variable when creating the struct:
FS_OBJ obj = { .status = /* something */, .dir_seach_idx = /* something */ };
You can't modify the const variable after creating the struct. Then you would have to remove the const keyword as mentioned by user3386109 in the comments.
I think const is not the right tool for what you are looking for. You can put data (structs) and behavior (functions) in a *.c file and provide public functions in the corresponding header file. This way you can mimic the equivalent c++ code that you want and hide the data and of course, you can define a constructor. A great book that might help is The GLib/GTK+ Development Platform. In chapter 3 you can find a good introduction to Semi-Object-Oriented Programming in C.
Here is a possible implementation, not necessarily the best one:
/src/main.c
#include <stdio.h>
#include "point.h"
int main()
{
Point *p1 = init(6, 7);
printf("%d\n", getX(p1));
printf("%d\n", getY(p1));
Point *p2 = init(12, 14);
printf("%d\n", getX(p2));
printf("%d\n", getY(p2));
setX(p2, 16);
printf("%d\n", getX(p2));
setY(p2, 16); /* error; we want y to initialize once and remain constant. Also accessing y with p2->y is an error too. */
printf("%d\n", getY(p2)); /* getY is ok */
freep(p1);
freep(p2);
}
/src/point.h
typedef struct _Point Point;
Point *init(int, int);
int getX(Point *);
void setX(Point *, int);
int getY(Point *);
void freep(Point *);
/src/point.c
#include <stdlib.h>
#include "point.h"
struct _Point{
int x;
int y;
};
Point *init(int x, int y)
{
Point *temp;
temp = malloc(sizeof(Point));
temp->x = x;
temp->y = y;
return temp;
}
int getX(Point *p)
{
return p->x;
}
void setX(Point *p, int x)
{
p->x = x;
}
int getY(Point *p)
{
return p->y;
}
void freep(Point *p)
{
free(p);
}
Furthermore, if we need a private method in our class, we do not provide a declaration of it in the header and also we use static to restrict its access within the class's file.
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;
}
Looking to see if anyone knows if its possible to swap C functions...?
void swap2(int(*a)(int), int(*b)(int)) {
int(*temp)(int) = a;
*a = *b;
*b = temp;
// Gives 'Non-object type 'int (int)' is not assignable
}
swap2(&funcA, &funcB);
EDIT
More data here as to intention -- Some answers have been provided below which do work such as creating the function ptr using typedef, pointing them to the functions and switching those, which lets you invoke the new swapped ptrs successfully.
BUT calling the functions by their original names after swapping shows no change. Essentially I'm looking for a c equivalent of the objc "swizzle".
I'm beginning to think this isn't possible, due to c's complete lack of reflection, and would require actually modifying the binary itself (obviously not feasible). D:
Comments welcome.
If you use the function pointers like below, it is yes
typedef int (*func_pt)(int);
func_pt a, b;
void swap(func_pt * a, func_pt * b)
{
func_pt tmp = *b;
*b = *a;
*a = tmp;
}
swap(&a, &b);
Or you use it as this, I think it is no:
int test1(int a)
{
return a;
}
int test2(int b)
{
return b;
}
swap(&test1, &test2);
Complete compiling working program
#include <stdio.h>
#include <stdlib.h>
typedef int (* func_pt)(int);
func_pt a, b;
int test1(int a)
{
printf("test1\n");
return 1;
}
int test2(int a)
{
printf("test2\n");
return 2;
}
void swap(func_pt * a, func_pt * b)
{
func_pt tmp = *b;
*b = *a;
*a = tmp;
}
int main(void)
{
a = &test1;
b = &test2;
printf("before\n");
a(1);
b(1);
swap(&a, &b);
printf("after\n");
a(1);
b(2);
return 0;
}
Output:
before
test1
test2
after
test2
test1
Some people do not try it by themselves, just say it absurd.So I give you a example.
I'm pretty sure you need pointers to function pointers to swap pointers, no? This type of swapping function swaps values; you really want to deal in addresses. The example function call wouldn't really work because C doesn't treat functions as first-class variables so you can't actually swap functions directly; you need to use pointers to function addresses, since addresses CAN be swapped:
void swap2(int(**a)(int), int(**b)(int)) {
int(*temp)(int) = *a;
*a = *b;
*b = *temp;
}
int(*func1)(int) = &foo;
int(*func2)(int) = &bar;
swap2(&func1, &func2);
Your code will give error like "invalid lvalue" at the time of assignment. As I can see in your code you are trying to swap pointers without changing its values so have a look on below solution.
void swap2(int(**a)(int), int(**b)(int)) {
int(*temp)(int) = *a;
*a = *b;
*b = temp;
}
int main(){
int(*temp1)(int) = &funcA;
int(*temp2)(int) = &funcB;
swap2(&temp1,&temp2);
}
Yes,you can. Think that a function-pointer is just a memory-address,the single requeriment is: where you will keep such address needs to be mutable. Say,int (*foo)() not really to where foo points to. May be to printf() or fopen().
Although the subject asks about swapping functions, you actually want to emulate what swizzle does. This just means you want to be able to call the same function name but have it do something different.
A pointer only solution will not give you that behavior. If that is not important to you, then you should adopt one of the function pointer only solutions provided. If it is important to you, then, you will need to introduce a layer of abstraction. The abstraction could use function pointers under the hood (although there are other solutions).
The API to users of this interface would be:
/* API to initialize */
void abstract_func_init ();
/* API to manipulate abstract functions */
typedef int abstract_func_type ();
abstract_func_type * abstract_func_get (abstract_func_type *key);
int abstract_func_set (abstract_func_type *key, abstract_func_type *behavior);
/* the abstract functions */
extern int foo ();
extern int bar ();
The implementation of such an interface could look like:
static void insert (abstract_func_type *key, abstract_func_type **behavior)
{ /* associate key to behavior */ }
static abstract_func_type ** lookup (abstract_func_type *key)
{ /* return behavior from key */ }
abstract_func_type * abstract_func_get (abstract_func_type *k) {
abstract_func_type **f = lookup(k);
if (f) return *f;
return 0;
}
int abstract_func_set (abstract_func_type *k, abstract_func_type *p) {
abstract_func_type **f = lookup(k);
if (f) {
*f = p;
return 0;
}
return -ENOENT;
}
#define DEFINE_ABSTRACT_FUNC(func) \
static int static_##func (); \
static abstract_func_type *func##_ptr = static_##func; \
int func () { return func##_ptr(); } \
static int static_##func ()
DEFINE_ABSTRACT_FUNC(foo) { return puts("foo"); }
DEFINE_ABSTRACT_FUNC(bar) { return puts("bar"); }
void abstract_func_init () {
insert(foo, &foo_ptr);
insert(bar, &bar_ptr);
}
Then, the swap() you initially presented in your post could be implemented like this:
void swap (abstract_func_type *a, abstract_func_type *b) {
abstract_func_type *ap = abstract_func_get(a);
abstract_func_type *bp = abstract_func_get(b);
abstract_func_set(a, bp);
abstract_func_set(b, ap);
}
Here is a program that calls swap():
puts("before swap");
foo();
bar();
swap(foo, bar);
puts("after swap");
foo();
bar();
And its output would be:
before swap
foo
bar
after swap
bar
foo
To automate the adding of abstract functions into the lookup table, you could introduce into the build system an extra step that called a script that would grep out the DEFINE_ABSTRACT_FUNC lines, and generate a new source file that had a function with the calls to insert() for each such line.
A complete version of the mock-up can be found here.
I'm new to C and I have a function that calculates a few variables. But for now let's simplify things. What I want is to have a function that "returns" multiple variables. Though as I understand it, you can only return one variable in C. So I was told you can pass the address of a variable and do it that way. This is how far I got and I was wondering I could have a hand. I'm getting a fair bit of errors regarding C90 forbidden stuff etc. I'm almost positive it's my syntax.
Say this is my main function:
void func(int*, int*);
int main()
{
int x, y;
func(&x, &y);
printf("Value of x is: %d\n", x);
printf("Value of y is: %d\n", y);
return 0;
}
void func(int* x, int* y)
{
x = 5;
y = 5;
}
This is essentially the structure that I'm working with. Could anyone give me a hand here?
You should use *variable to refer to what a pointer points to:
*x = 5;
*y = 5;
What you are currently doing is to set the pointer to address 5. You may get away with crappy old compilers, but a good compiler will detect a type mismatch in assigning an int to an int* variable and will not let you do it without an explicit cast.
void function(int *x, int* y) {
*x = 5;
*y = 5;
}
would change the values of the parameters.
In addition to the changes that the other posters have suggested for your function body, change your prototype to void func(int *,int *), and change your function definition (beneath main) to reflect void as well. When you don't specify a return type, the compiler thinks you are trying to imply an int return.
You can't forward declare func(int,int) when in reality it is func(int*, int*). Moreover, what should the return type of func be? Since it doesn't use return, I'd suggest using void func(int*, int*).
You can return a single variable of a struct type.
#include <stdio.h>
#include <string.h>
struct Multi {
int anint;
double adouble;
char astring[200];
};
struct Multi fxfoo(int parm) {
struct Multi retval = {0};
if (parm != 0) {
retval.anint = parm;
retval.adouble = parm;
retval.astring[0] = parm;
}
return retval;
}
int main(void) {
struct Multi xx;
if (fxfoo(0).adouble <= 0) printf("ok\n");
xx = fxfoo(42);
if (strcmp(xx.astring, "\x2a") == 0) printf("ok\n");
return 0;
}
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.