I have a struct and want to sort an array of the struct using merge sort.
I need to pass the sorting parameter to the merge function and access the struct members.
Can this be done in C?
example:
struct movie_imdb_data {
char color[15];
char director_name[100];
int num_critic_for_reviews;
int duration; /// in min not date and time
int director_facebook_likes;
int actor_3_facebook_likes;
char actor_2_name[100];
int actor_1_facebook_likes;
int gross;
};
in the main function, I have:
if (argc > 2) {
column_sort = argv[2];
}
now I want to call merge_sort(<array of struct>, <column_sort *>)
can I access the member in the array as array[0]->column_sort to compare?
now I want to call merge sort and pass the
I want to pass the array and the sorting parameter (that I need the array sorted by) can I use a variable in place of a members name ie..
arr[1].column_sort
instead of
arr[1].color
Sounds like you want to take a command line argument specifying the name of the field to sort on and then sort on that field.
For that, try code like:
#include <stdlib.h>
#include <string.h>
/* compare function for field 3: "num_critic_for_reviews" */
int compField3(const void *a, const void *b)
{
struct movie_imdb_data* aStruct = (struct movie_imdb_data*)a;
struct movie_imdb_data* bStruct = (struct movie_imdb_data*)b;
return (aStruct->num_critic_for_reviews < bStruct->num_critic_for_reviews)?
-1: (aStruct->num_critic_for_reviews > bStruct->num_critic_for_reviews)?
+1: 0;
}
/* also define other compare functions for each field */
int main()
{
const char* columnName = argv[2];
struct movie_imdb_data* parray;
parray = your-array;
int (*comp)(const void *, const void *, void *) = 0;
/* map the column name to compare function for that column */
if (strcmp(columnName, "num_critic_for_reviews") == 0)
{
comp = compField3;
}
/* map other names to compare function for column */
else if (...) {...}
else { exit(1); /* if not recognized column name */ }
qsort(parray, numElementsOfArray, sizeof(struct movie_imdb_data), comp);
...
}
Hope this helps!
There are different approaches to your problem:
you can write separate functions to compare structures on specific fields. In main, you would select the appropriate comparison function by testing the name of the field (or possibly generic names that are not field names). You would then pass this comparison function to mergesort (or qsort...).
if all members have the same type, you could determine the offset of the field from the beginning of the structure with macros offsetof(type, member). There is no generic way to compute these offsets, you need to write a series of tests or use a table. The comparison function would use casts to access the members:
size_t member_offset = offsetof(struct movie_imdb_data, duration);
int comp_int_member(const void *a1, const void *a2) {
const int *p1 = (const int *)((const unsigned char*)a1 + member_offset);
const int *p2 = (const int *)((const unsigned char*)a2 + member_offset);
return (*p1 > *p2) - (*p1 < *p2);
}
The downside of this latter approach is it can only handle fields with a given type.
Related
I am sorting/searching a struct array.
struct Substance
{
char name[NAME_SIZE]
int mass;
double halftime;
}
The sorting/searching is done after prompting the user to choose what member of the struct to sort by, i.e by name, mass or halftime.
Is there a way to make a general function that can work with all of the three data types or do I have to write different functions for each?
The reason why I don't want to write several functions is that 90% of the code in each function would be the same.
I am especially struggling with the fact that I have to get the member I want to operate on for each iteration, i.e substances[i].mass to access the mass and this syntax obviously has to be different for each member of the struct.
I tried to do some pre processing to avoid this issue:
switch(choice)
{
case '1':
memcpy(current, substances[i].name, NAME_SIZE);
break;
case '2':
sprintf(current, "%d", substances[i].mass);
break;
case '3':
sprintf(current, "%lf", substances[i].halftime);
}
But if I want to sort by mass I would then have to convert every other substance's mass in the struct array aswell.
I have also thought about representing every member as the same data type in the first place and then just convert in when needed, like printing, writing to file etc but I don't know what data type I would use.
A general use case would be:
/*
Do you want to sort by (1) name, (2) mass or (3) halftime: 2
Sorted list by mass:
Name Mass Halftime
Zirconium 91 ...
Radon 220 ...
Radon 222 ...
Uranium 238 ...
*/
Yes qsort(). example:
Given struct:
struct Substance
{
char name[NAME_SIZE]
int mass;
double halftime;
};
And assuming array defined substances[N];//has been populated, then examples of calls can be:
qsort(substances, N, sizeof (struct Substance), compareName);
qsort(substances, N, sizeof (struct Substance), compareMass);
qsort(substances, N, sizeof (struct Substance), compareHtime);
...with the forms for your compare functions being passed in qsort() being:
int compareName(const void *a, const void *b)
{
const struct Substance *ia = a;
const struct Substance *ib = b;
return strcmp(ia->name, ib->name);//returns -1, 0 1 per strcmp rules
}
int compareMass(const void *a, const void *b)
{
const struct Substance *ia = a;
const struct Substance *ib = b;
return ia->mass == ib->mass ? 0 :
ia->mass > ib->mass ? 1 : -1;
}
int compareHtime(const void *a, const void *b)
{
const struct Substance *ia = a;
const struct Substance *ib = b;
return fabs(ia->halftime - ib->halftime) < 0.00001 ? 0 :
(ia->halftime - ib->halftime) > 1 ? 1 : -1;
}
"Is there a way to make a general function that can work with all of the three data types or do I have to write different functions for
each?"
You could create a void function that uses your switch(), and uses an enum. to decide which of the three compare functions to call. Eg:
enum {
NAME,
MASS,
HALF,
TYPE_MAX
};
void sort(struct Substance *s, size_t size, int type)
{
switch(type)
case NAME;
qsort(s, size, sizeof (struct Substance), compareName);
break;
case
...
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);
}
I'm attempting to sort a directory listing based on the most recent st_mtime, and having trouble figuring out how exactly to sort the struct array I'm allocating. How can I sort the struct according to the most recent date?... here's my current approach:
static int cmpstringp(const void *p1, const void *p2){
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
struct directoryStat dStat{
char name[50];
char time[50];
};
int main(){
i = 0;
while ((ep = readdir(dp))){
stat(ep->d_name, &fileStat);
strcpy(dStat[i].name, ep->d_name);
strcpy(dStat[i].time, ctime(&fileStat.st_mtime));
i++;
}
}
qsort(dStat, i, sizeof(char), cmpstringp);
Sorting time (or datetime)-values based on their string representations might not be a good idea, because this (lexicographical) order based on a probably localization-dependent string representation of a date/time-value might then not correspond to the chronological order (cf., for example, David C. Rankin's comment). I'd store and compare the raw time_t-values instead.
See the following code, which demonstrates both, sorting by a string value and sorting by a time_t-value. Hope it helps!
typedef struct directoryStat {
char name[50];
char timeStr[50];
time_t timeVal;
}dStat;
int cmpDStatTimeStr(const void *p1, const void *p2){
return strcmp( ((dStat*)p1)->timeStr, ((dStat*)p2)->timeStr);
}
int cmpDStatTimeVal(const void *p1, const void *p2){
return ((dStat*)p1)->timeVal > ((dStat*)p2)->timeVal;
}
int main(){
dStat stat[2] = { { "the former", "2017/5/2", 14500000 }, { "the latter","2017/5/12", 14500001 }};
// sort based on string value (lexigraphical comparison):
qsort(stat, 2, sizeof(dStat), cmpDStatTimeStr);
// sort based on time value directly:
qsort(stat, 2, sizeof(dStat), cmpDStatTimeVal);
return 0;
}
I'm a newbie with C language and I need to make a function to sort an array of struct Student data types (after the element Student.ime alphabetically). I am not really sure where to put the pointers so I can return the new array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
int id;
char ime[20];
char prezime[20];
char brindexa[20];
struct Datum datum_rodjenja;
};
struct Student sortiraj(struct Student niz[], int vel)
{
int i, j;
struct Student tempo;
tempo = niz[0];
for(j=0 ; j<vel ; j++)
{
for(i=j ; i<vel ; i++)
{
if(strcmp(tempo.ime,niz[i].ime)>0)
{
tempo = niz[i];
}
i++;
}
niz[j] = tempo;
j++;
}
return niz;
}
The array is stored in a .txt file but that is not the problem. One more thing, how do I call the function in the main(). I thought maybe like this?
niz=sortiraj(niz, vel);
Can someone give me any tips please. Thank you.
You seem to be sorting the array in-place, so you don't really need to return it at all. Also, use the standard library function qsort():
int cmp(const void *ap, const void *bp)
{
const struct Student *a = ap, *b = bp;
return strcmp(a->ime, b->ime);
}
struct Student students[] = { /* whatever */ };
qsort(
students,
sizeof(students) / sizeof(studends[0]),
sizeof(students[0]),
cmp
);
Also, please use English function and variable names.
Have you considered using the qsort() function? Example:
If you have an array of strings say strings, (Note: not an array of structs), with the number of strings being say, cnt then:
qsort(strings, cnt, sizeof(char*), sortstring);
With the function sortstring defined as:
static int sortstring( const void *str1, const void *str2 )
{
const char *rec1 = *(const char**)str1;
const char *rec2 = *(const char**)str2;
int val = strcmp(rec1, rec2);
return val;
}
//for a simple test, run this main with the code above:
int main(void)
{
char *strings[]={"this", "is", "a", "test", "of", "the", "qsort", "function", "to", "try"};
int strlen = sizeof(strings)/sizeof(char *);
qsort(strings, strlen, sizeof(char *), sortstring);
return 0;
}
//Note my environment required #include <ansi_c.h>
First of all, your function signature is not marked return type as an Array of Students. Second of all, I don't know which sorting algorithm you're trying to use, but your implementation isn't right.
If you correct your function signature, you shouldn't get any error by the way you're calling the:
struct Student* sortiraj(struct Student niz[], int vel)
tips about your sortiraj: Check either selection sort or bubble sort for your sort algorithm. And for further study, you can check some recursive algorithms like merge sort and quick sort which are more advance and you need more programming knowledge to implement them.
Change the return type of function sortiraj to void.
Create and fill the struct Student niz[] array in function main.
From function main, pass the array and its length (vel) to function sortiraj.
And of course, no need to return anything from function sortiraj (as implied in section 1).
Since you are passing in a pointer, namely niz, you are changing the memory that niz points to. This means that you don't have to return niz.
However if you want to return niz your function's return type must be the same type as niz. Currently you have a return type of just struct Student so you should be getting a compilation error.
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.