Author Topic: [C] - Passing a structure member as a parameter to a function  (Read 10732 times)

0 Members and 3 Guests are viewing this topic.

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Hello,

I need some help / suggestions to do this in a better fashion. I would be very grateful for any suggestions and help.
The problem is this - I need to pass a structure member as a parameter to a function to set or clear some variables.

Presently, the best i could come up with is this

Code: [Select]
myfunction(mystruct_t *structure, char *key, char *value)
{
   if (strncmp(desired_value_1, key, size) ==0)
       {//do stuff}
   if (strncmp(desired_value_2, key, size) ==0)
       {//do other stuff}
   if (strncmp(desired_value_1, key, size) ==0)
       {//do yet anotherstuff}
}

As you can see, it is not very scalable nor elegant. I was wondering if it is possible to pass a "generic" struct member as an argument and just do the comparision against the structure passed in. Like so.

Code: [Select]
myfunction(mystruct_t *structure, struct_member *key, char *value)
{
   if (strncmp(desired_value_1,structure->key, size) == 0)
       {//do stuff}
   if (strncmp(desired_value_2,structure->key, size) == 0)
       {//do other stuff}
   if (strncmp(desired_value_3,structure->key, size) == 0)
       {//do yet anotherstuff}
}

obviously the type "struct_member" is just something I made up.. but it would allow the flexibility of reusing the logic to compare against any arbitrary data type. The second advantage I can think of is to ensure that it would obviously fail when the structure doesnt have the member defined in it. Third, it would allow me to use enumerations for th comparision, getting rid of unwieldy string operators and libraries.


Consequently, is there any way where I can simply use a char* to access a struct member, like so.

Code: [Select]
myfunction(mystruct_t *structure, char *key, char *value)
{
   if (structure->key == 0)
       {//do stuff}
   if (structure->key == 2)
       {//do other stuff}
  if (structure->key == 99)
       {//do yet anotherstuff}
}

I know I am sort of overreaching.. but I was hoping someone came up with a more elegant solution to this..

Thanks in advance!!

PS: Almost forgot to mention, this is for a microcontroller application, not a desktop one.
If god made us in his image,
and we are this stupid
then....
 

Offline madires

  • Super Contributor
  • ***
  • Posts: 9172
  • Country: de
  • A qualified hobbyist ;)
Re: [C] - Passing a structure member as a parameter to a function
« Reply #1 on: July 20, 2020, 08:03:30 pm »
Linked list with TLV approach?
 

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Re: [C] - Passing a structure member as a parameter to a function
« Reply #2 on: July 20, 2020, 08:18:59 pm »
Linked list with TLV approach?

I am not sure what you mean.. I am not seeing how you can link linked lists :-P with a structure..
However, I am interested in learning more and I do not have an idea what TLV means ( A quick google says it stands for "Type Length Value" , but that is a reading for tonight..)

Doesnt it complicate it a lot?? Given the additional complexity, it might be easier to just have a switch cases and string comparision I suppose..
Also a limiting factor is my time to learn and implement.. While I am not on a deadline ( it is a hobby project for skill sharpening), I would like to
1. Keep it well documented.
2. Keep the code clean and readable / understandable.

Thank you for the suggestions anyway.. :-) If it is not too much trouble, can you provide an example? even pseudocode will do.. I just need to visualize the context you are suggesting in my head...
If god made us in his image,
and we are this stupid
then....
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 12463
  • Country: us
    • Personal site
Re: [C] - Passing a structure member as a parameter to a function
« Reply #3 on: July 20, 2020, 08:28:39 pm »
I'm not sure I fully understand what you actually need. There is no way to access a structure member by name stored in the variable, since that would need a run-time evaluation.

But at the same time I don't really understand why you would need something like this. Can you create a more complete example of what you need?

You can possibly minimize the amount of duplicate code with macros, but In many case it is not worth the added obscurity.
« Last Edit: July 20, 2020, 08:30:16 pm by ataradov »
Alex
 

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Re: [C] - Passing a structure member as a parameter to a function
« Reply #4 on: July 20, 2020, 08:39:24 pm »
I'm not sure I fully understand what you actually need. There is no way to access a structure member by name stored in the variable, since that would need a run-time evaluation.

But at the same time I don't really understand why you would need something like this. Can you create a more complete example of what you need?

You can possibly minimize the amount of duplicate code with macros, but In many case it is not worth the added obscurity.

I am sorry, I should have provided a much more clearer example in my first post.

I have a a C struct, whose members I need to modify. I wanted to create a generic function to set any member of that struct. Like so

Code: [Select]
EXIT_STATUS SetPayloadKey(SensorPayload_t *payload, char *key, char *value);

Now, the structure itself has some ints, some floats, some char arrays..
And as I mentioned in the first post, It is doable by doing a string compare on the "key" and set / clear the members inside the logic.
However, it is limited to one type of struct. If I have multiple different structures, then I would need multiple such function each for a specific type of struct.
So I was wondering if it is in fact possible to have a generic function like so where the underlying logic is simply the equivalent of this.

Code: [Select]
SetPayloadKey(SensorPayload_t *payload, char *key, char *value){

payload -> key = value;

I can reuse this module for different types of structures.

I hope I made a little more sense :-).

It is a little lofty for generalizing across multiple structs.. but I am presently interested in just setting a member for one type of structure by passing the key directly.

Thank you! :-)
« Last Edit: July 20, 2020, 08:42:00 pm by krish2487 »
If god made us in his image,
and we are this stupid
then....
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 12463
  • Country: us
    • Personal site
Re: [C] - Passing a structure member as a parameter to a function
« Reply #5 on: July 20, 2020, 08:45:50 pm »
If "key" is a variable known only in run-time, then there is no way to do that. It is just too much logic compiler would have to generate. You would also need to know the size (type) of the field by its name.

It is possible to simplify the code from a complete copy-paste using macros, but it is really only worth it if you have more than 15-20 fields. Otherwise just do the manual thing.
Alex
 
The following users thanked this post: krish2487

Offline madires

  • Super Contributor
  • ***
  • Posts: 9172
  • Country: de
  • A qualified hobbyist ;)
Re: [C] - Passing a structure member as a parameter to a function
« Reply #6 on: July 20, 2020, 08:47:14 pm »
What I've meant is to use linked lists instead of the structures. And each list element would contain a TLV set to manage your data. T(ype) would be the data type, L(ength) the data length and V(alue) the data itself. You could encode your structure members as type or add another variable as identifier, something like ID to identify the variable's name. This way you can simply search the linked list for an element with the ID of "name" and perform whatever check you like. The TLV part allows you to choose the right check, e.g. comparing strings or numbers. If linked lists are completely new to you then take your time.
« Last Edit: July 20, 2020, 08:53:59 pm by madires »
 

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Re: [C] - Passing a structure member as a parameter to a function
« Reply #7 on: July 20, 2020, 08:59:22 pm »
If "key" is a variable known only in run-time, then there is no way to do that. It is just too much logic compiler would have to generate. You would also need to know the size (type) of the field by its name.

It is possible to simplify the code from a complete copy-paste using macros, but it is really only worth it if you have more than 15-20 fields. Otherwise just do the manual thing.

Unfortunately, it is known at runtime.. So you are right.. It is easier to do the check manually.

What I've meant is to use a linked list instead of the structure-. And each list element would contain a TLV set to manage your data. T(ype) would be the data type, L(ength) the data length and V(alue) the data itself. You could encode your structure members as type or add another variable as identifier, something like ID to identify the variable's name. This way you can simply search the linked list for an element with the ID of "name" and perform whatever check you like. The TLV part allows you to choose the right check, e.g. comparing strings or numbers. If linked lists are completely new to you then take your time.

With structures you could do some pointer magic but you need to know the data type of each member. If you group members of the same data type it would become a little bit easier, but it will be still quite ugly.

It is an elegant way on handling it! :-) Thank you. I am a greenhorn with linked lists.. I read about them.. but never had any use.. However, always a first time for everything..
If I am understanding you right.. this is what you are suggesting.

Code: [Select]
{
char *member_name;
int ID;
char *Type;
int Length;
char *Value;
linked_list *next_member;
} linked_list;

sorry.. I could only think of it as a C struct. :-P I can see where it adds some typechecking abilities.. But I will probably read up and try to see if I can implement it, provided my understanding of your suggestion is correct.
If god made us in his image,
and we are this stupid
then....
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 12463
  • Country: us
    • Personal site
Re: [C] - Passing a structure member as a parameter to a function
« Reply #8 on: July 20, 2020, 09:06:39 pm »
The linked list is a total overkill, and it will end up messier than just a simple bunch of if statements.
Alex
 

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Re: [C] - Passing a structure member as a parameter to a function
« Reply #9 on: July 20, 2020, 09:14:33 pm »
The linked list is a total overkill, and it will end up messier than just a simple bunch of if statements.

Oh yes definitely, for my application. I figured it might be a skill useful for later.. :-)
I have, for the record, about 7-8 members in any given struct. It is much much easier doing a simple lookup using strncmp.
If god made us in his image,
and we are this stupid
then....
 

Offline madires

  • Super Contributor
  • ***
  • Posts: 9172
  • Country: de
  • A qualified hobbyist ;)
Re: [C] - Passing a structure member as a parameter to a function
« Reply #10 on: July 20, 2020, 09:19:23 pm »
Yep, the element of a linked list is a structure with data and a pointer to the next element. A variant is the doubly linked list with an additional pointer to the previous element. BTW, use typedef:

Code: [Select]
typedef struct element
{
  uint8_t ID;
  uint8_t Type;
  uint8_t Length
  void *Value
  struct element *Next;
} element_type;

And yes, it's a pointer nightmare. ;D
« Last Edit: July 20, 2020, 09:21:04 pm by madires »
 
The following users thanked this post: krish2487

Offline madires

  • Super Contributor
  • ***
  • Posts: 9172
  • Country: de
  • A qualified hobbyist ;)
Re: [C] - Passing a structure member as a parameter to a function
« Reply #11 on: July 20, 2020, 09:27:01 pm »
The linked list is a total overkill, and it will end up messier than just a simple bunch of if statements.

I wouldn't recommend to use linked lists on 8 bit MCUs. ;)
 

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Re: [C] - Passing a structure member as a parameter to a function
« Reply #12 on: July 20, 2020, 09:28:40 pm »
Yep, the element of a linked list is a structure with data and a pointer to the next element. A variant is the doubly linked list with an additional pointer to the previous element. BTW, use typedef:

Code: [Select]
typedef struct element
{
  uint8_t ID;
  uint8_t Type;
  uint8_t Length
  void *Value
  struct element *Next;
} element_type;

And yes, it's a pointer nightmare. ;D

Very elegant!! :-) Thank you.. It is much more clearer now.
As I have mentioned earlier.. it is an overkill for my application.. but it actually might  be a more appropriate solution for a problem elsewhere!! :-D
If god made us in his image,
and we are this stupid
then....
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 22435
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: [C] - Passing a structure member as a parameter to a function
« Reply #13 on: July 20, 2020, 10:16:16 pm »
So you want to use the struct, with the function call, as you would use an associative array in a high level language (HLL)?

For example, in JavaScript you can use:
Code: [Select]
foo["bar"] = baz;which is equivalent to
Code: [Select]
foo.bar = baz;and this will set the property bar to the value of baz.

In C, we need to construct all the data structures to hold these.

This might be a good lesson on the internals of HLLs --

On the one hand, it's a PITA to do in C.  On the other, it may give you a great appreciation for all the hard work HLLs have to do, and why you might give them more patience for being slow, when they're so powerful.  (and really, with the aggressive optimizations used in the most prominent languages, they're not very slow at all; an extremely impressive feat!)

One way JS might do this, is to store an "Object" as a structure in memory.  The structure contains a type descriptor, so the interpreter can tell what it's looking at; and a pointer to the data thus described.  The null object might have type 0 (and the data is irrelevant because it's never read), int 1, etc.  Arrays, other Objects, and hybrids (mixed sets of objects, arrays or primitives) can be enumerated as well.

When we ask about properties of an object, we might be referring to an Object of, say, PropertyArray type, which contains key-value pairs.  Say we do:
Code: [Select]
foo.one = "Apple";
foo.two = "Banana";
foo.three = "Cherry";
The interpreter might execute this and construct a PropertyArray whose data might be written in C like:
Code: [Select]
PropertyArray foo_p = {
    struct {char* key = "one", char* value = "Apple"},
    struct {char* key = "two", char* value = "Banana"},
    struct {char* key = "three", char* value = "Cherry"}
}

When foo is accessed later,
Code: [Select]
console.log(foo.one);
foo.one = "Avocado";
a function is called which reads this PropertyArray, checking for the specified key, and returns or assigns a new value:
Code: [Select]
printf("%s", getPropertyValueString(&foo, "one");
setPropertyValue(&foo, "one", "Avocado");

...I take it you're interested in the latter operation, then?

We might break down the setting operation as getting a pointer to the PropertyArray's value member, and modifying it:
Code: [Select]
char** tmp = getPropertyValue_p(&foo, "one"); // found key; returns pointer to foo_p[0].value
mark_for_garbage_collection(*tmp);
*tmp = malloc(strlen("Avocado"));
strcpy(*tmp, "Avocado");

(Note we might be keen to mark the now-slightly-orphaned object for garbage collection.  That is, to check if it has any other pointers to it in current context, and to free it if it's now completely orphaned.  Garbage collection can also be done on its own, without such tips; it's up to the design of the VM.  In C, we need to do this, explicitly, and carefully.  Never free()ing the object results in a leak, while free()ing it unconditionally may leave a dangling pointer.  Both are dangerous.  So you can see, there is a lot of value added by automatic garbage collection.)

To further implement this, we need some way to store properties.  If we are using dynamic memory (as in the HLL case), the PropertyArray can be anywhere in memory, and as we add and remove items from it, its size can vary; this is a normal dynamic array operation, the implementation of which can be found anywhere.  We keep track of it with foo.

If we are allocating static types and properties, we might use a fixed array, and perhaps also split it into two arrays (char* keys[NUM_KEYVALUEPAIRS] and char* values[NUM_KEYVALUEPAIRS]) which can be a minor optimization.  We might merge both into foo's type, so that it's a pair of fixed-length arrays.  Or we might use a struct with useful member names, the same names being enumerated in the keys array, and the value array then gets offsets of foo's members; and perhaps their type or size/length as well, depending on what types and how general you want to get.

If the member assignments should have side-effects, you can also put together an array of function pointers; this reduces your stack of if-statements to a simple loop on strcmp, then performing the one operation on the element thus located.


A note on security: if any of these should be somehow user-writable, be very careful about buffer overruns, in static, dynamic (heap) or stack memory; and be especially careful of executing function pointers from RAM.  A buffer overflow exploit is one thing; or jumping to a null pointer, another; but literally jumping to a potentially-user-controlled pointer is just putting it on a silver platter!  If these data structures should be static, putting them in read-only memory (when an MMU is present) can help.  (For global variables, set them as const, and any other attributes as necessary for the platform -- for example, AVR uses PROGMEM to place variables in Flash memory, and requires accessor functions to utilize.  For functions, set them as static const, which will place them in global data rather than on the stack.)

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline dmills

  • Super Contributor
  • ***
  • Posts: 2093
  • Country: gb
Re: [C] - Passing a structure member as a parameter to a function
« Reply #14 on: July 20, 2020, 10:43:14 pm »
The offsetof macro may be your friend here.
Completely untested...

Code: [Select]
struct foo {
 int bar;
 int baz;
};

void fn (void * s, uint32_t offset, int value){
int * ptr = (int*)((uint8_t*)s + offset);
*ptr = value;
}

int main () {
 struct foo f;
 fn (&f, offsetof (struct foo, bar), 5); // set f.bar to 5
 fn (&f, offsetof (struct foo, baz),10); // set f.baz to 10
 return 0;
}

There is another trick you can exploit, in that you could use the upper few bits in the member parameter to encode a type, so that you write the correct number of bytes. Obviously this relies upon all your structures having unused bits in the top and I would probably wrap the doings in a few macros to make things simpler....

Nice thing about this is that fn need have NO knowledge of the type of the structure, and in fact does not even need the structure declaration to be visible.


« Last Edit: July 20, 2020, 10:50:36 pm by dmills »
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 12463
  • Country: us
    • Personal site
Re: [C] - Passing a structure member as a parameter to a function
« Reply #15 on: July 20, 2020, 10:46:47 pm »
offsetof() will not help if you are getting the name of the member from outside of the program as a string.
Alex
 

Offline dmills

  • Super Contributor
  • ***
  • Posts: 2093
  • Country: gb
Re: [C] - Passing a structure member as a parameter to a function
« Reply #16 on: July 20, 2020, 10:57:48 pm »
True obviously, but it can be a reasonable thing to store in a table that defines how to set something when the string matches (And this way the file load and save functions do not need visibility of the metadata or the declaration of the structure they are reading or writing).

I am quite fond of static const tables of {name, type, offset, lower limit, upper limit, default value} for everything from parsing commands to loading and saving files, I likes my textual representations as load and save files, makes hand hacking them easy.

 

Offline magic

  • Super Contributor
  • ***
  • Posts: 8058
  • Country: pl
Re: [C] - Passing a structure member as a parameter to a function
« Reply #17 on: July 21, 2020, 05:59:04 am »
offsetof() will not help if you are getting the name of the member from outside of the program as a string.
It's not clear if OP is really getting the name of the member from outside the program. If that's not the case, simply removing the "" from the member's name will solve the biggest problem and possibly enable some kludge involving macros.

If OP really gets the names as text from outside the program, then the structures should be ditched and replaced with a key-value store. It doesn't need to be in the form of a list, this will work too:
Code: [Select]
struct kv {
  char *key;
  char *value;
  int value_size;
};
struct kv kv_store_with_10_elements[10];
Hopefully you can imagine how to use that. This assumes that the external code treats the stored values as blobs of bytes and knows how to cast them to the intended types. If not, you could add another member to encode type of the stored value and write accessor function for every possible type... That would be easier in C++, probably.
« Last Edit: July 21, 2020, 06:01:26 am by magic »
 

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Re: [C] - Passing a structure member as a parameter to a function
« Reply #18 on: July 21, 2020, 09:45:20 am »
@Teslacoil.
Yes, that is the lofty goal! :-) . However it looks like it is impractical for such a small application as mine.
However, that was an interesting read about how HLL operate and simplify some things. Thank you for that!



The offsetof macro may be your friend here.
Completely untested...

Code: [Select]
struct foo {
 int bar;
 int baz;
};

void fn (void * s, uint32_t offset, int value){
int * ptr = (int*)((uint8_t*)s + offset);
*ptr = value;
}

int main () {
 struct foo f;
 fn (&f, offsetof (struct foo, bar), 5); // set f.bar to 5
 fn (&f, offsetof (struct foo, baz),10); // set f.baz to 10
 return 0;
}

There is another trick you can exploit, in that you could use the upper few bits in the member parameter to encode a type, so that you write the correct number of bytes. Obviously this relies upon all your structures having unused bits in the top and I would probably wrap the doings in a few macros to make things simpler....

Nice thing about this is that fn need have NO knowledge of the type of the structure, and in fact does not even need the structure declaration to be visible.




Interesting!!! I was not aware of this macro.. looks like it miight provide an easier solution.. I ll try and mock something up with this. Thank you.

offsetof() will not help if you are getting the name of the member from outside of the program as a string.
True.. However, If I map the struct member names to a enumeration. Then I can pass the name as an enum literal to the function and translate that enum into an offset.

offsetof() will not help if you are getting the name of the member from outside of the program as a string.
It's not clear if OP is really getting the name of the member from outside the program. If that's not the case, simply removing the "" from the member's name will solve the biggest problem and possibly enable some kludge involving macros.

If OP really gets the names as text from outside the program, then the structures should be ditched and replaced with a key-value store. It doesn't need to be in the form of a list, this will work too:
Code: [Select]
struct kv {
  char *key;
  char *value;
  int value_size;
};
struct kv kv_store_with_10_elements[10];
Hopefully you can imagine how to use that. This assumes that the external code treats the stored values as blobs of bytes and knows how to cast them to the intended types. If not, you could add another member to encode type of the stored value and write accessor function for every possible type... That would be easier in C++, probably.

Precisely my thoughts.. :-)
I do not really need to use a char* for a key name.. I did not / could not come up with a more clearer fashion to indicate the struct member.. However, using the offset macros, I might be able to pass an enum directly without using char* .
I dont get the names from outside the program.. But it passed during runtime.. For information.. It is running on a STM32F1 micro for a data logger application.

The key value stores is the end goal here however... This data will be finally transformed to a JSON string to be sent to a server.. It might actually be easier for me to use a key-value type datastructure right from the beginning..
Thank you for the ideas and suggestions.. :-)

 
If god made us in his image,
and we are this stupid
then....
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4564
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: [C] - Passing a structure member as a parameter to a function
« Reply #19 on: July 21, 2020, 11:14:00 am »
I suspect you're dealing with device parameters/settings?
Then key-value list is the way to go internally.

Code: [Select]
struct listItem {
    const char *name;
    int key;
    enum itemType type;
    union {
        void (*getInteger)(int key, int * const data);
        void (*getFloat)(int key, float * const data);
         ...
    } getters;
    union {
        void (*setInteger)(int key, const int * const data);
        void (*setFloat)(int key, const float * const data);
         ...
    } setters;
};

void getInteger(int key, int * const data){
    find in list
    check type
    call getInteger (or getFloat if it was getFloat)
}
And either split over files or just in one bunch:
Code: [Select]
const struct listItem settings[] = { ... };

void getInteger_randomSettingsForThing(int key, int * const data){
    *data = convertToMetricFromInternalUnit( yourstruct.member );
}

If someone want to set some key they can call setInteger(key, data)
and your top function looks in the list consisting of above entries if that is a valid option
and calls the specific function referenced in the item to deal with the action required when setting the value going with the key.
Where you actually store the value is irrelevant, this method eliminates global variables and adds options to do range checks or type conversions.
And it doesn't require casts so it's "type safe". Compared to passing everything via char pointers.

If it isn't for device parameters/settings then just ignore this.
« Last Edit: July 21, 2020, 11:17:55 am by Jeroen3 »
 

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Re: [C] - Passing a structure member as a parameter to a function
« Reply #20 on: July 21, 2020, 11:31:38 am »
I suspect you're dealing with device parameters/settings?
Then key-value list is the way to go internally.

Code: [Select]
struct listItem {
    const char *name;
    int key;
    enum itemType type;
    union {
        void (*getInteger)(int key, int * const data);
        void (*getFloat)(int key, float * const data);
         ...
    } getters;
    union {
        void (*setInteger)(int key, const int * const data);
        void (*setFloat)(int key, const float * const data);
         ...
    } setters;
};

void getInteger(int key, int * const data){
    find in list
    check type
    call getInteger (or getFloat if it was getFloat)
}
And either split over files or just in one bunch:
Code: [Select]
const struct listItem settings[] = { ... };

void getInteger_randomSettingsForThing(int key, int * const data){
    *data = convertToMetricFromInternalUnit( yourstruct.member );
}

If someone want to set some key they can call setInteger(key, data)
and your top function looks in the list consisting of above entries if that is a valid option
and calls the specific function referenced in the item to deal with the action required when setting the value going with the key.
Where you actually store the value is irrelevant, this method eliminates global variables and adds options to do range checks or type conversions.
And it doesn't require casts so it's "type safe". Compared to passing everything via char pointers.

If it isn't for device parameters/settings then just ignore this.

It looks self contained more or less.. AFAICS. However wouldnt that require that you need one such structure for every different type of data structures you are trying to maintain? And If I understand it right.. the same unions for setters and getters can also be extended for a char* type or boolean type.
Thank you for the suggestions though! :-)

PS: Yes, it is for device parameters / settings.. However, It is not just for device parameters.. I am also looking to generalize it for Self Test results and the payload to be sent to a server, once data is ready..
« Last Edit: July 21, 2020, 11:33:44 am by krish2487 »
If god made us in his image,
and we are this stupid
then....
 

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Re: [C] - Passing a structure member as a parameter to a function
« Reply #21 on: July 21, 2020, 11:50:36 am »
For sake of completeness
This is one such data structure I have.

Code: [Select]
typedef struct GPS_Payload{

char* Device_Token;
float Latitude;
float Longitude;
float Altitude;
uint8_t Fix_Type;

} Payload;
and this is another
Code: [Select]
typedef struct Dev_Settings{
bool PMS5003_Enabled;
bool ECC508_Enabled;
bool ADS1015_Enabled;
char* Device_Token;
uint8_t Interval;

} SensorSettings;

I am basically, trying to make an easy job hard and come up with a way of making a generic function that can take pointers to (either) structures, structure members and values to set as arguments and operate accordingly.

If god made us in his image,
and we are this stupid
then....
 

Offline magic

  • Super Contributor
  • ***
  • Posts: 8058
  • Country: pl
Re: [C] - Passing a structure member as a parameter to a function
« Reply #22 on: July 21, 2020, 12:10:37 pm »
Why would you even want a generic code to work with sturctures that have nothing in common with each other?

How will your generic code deal with being given different types of arguments at different times?

Suppose that structure->key really works in the example below,
Code: [Select]
myfunction(mystruct_t *structure, struct_member *key, char *value)
{
   if (strncmp(desired_value_1,structure->key, size) == 0)
       {//do stuff}
what's supposed to happen if structure->key isn't actually a text but a float?

Maybe you can simply write your function like that:
Code: [Select]
myfunction(char *key, char *value, size_t len, char *somethingelse) {
 if (!strncmp(vaule, key, len)) {
  blah blah do something with somethingelse
 }
}

myfunction(&GPS_whatever.foo, "magic value", &GPS_whatever.bar);
It would probably take a bit of casting...

The thing is, C is not a dynamic language. It won't do typechecking at runtime for you. When you write code, you need to know which things will have which type in advance, or treat everything as char[] and then structures don't matter, just pass char* around.
« Last Edit: July 21, 2020, 12:14:30 pm by magic »
 

Offline krish2487Topic starter

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: dk
Re: [C] - Passing a structure member as a parameter to a function
« Reply #23 on: July 21, 2020, 12:20:24 pm »
Why would you even want a generic code to work with sturctures that have nothing in common with each other?

How will your generic code deal with being given different types of arguments at different times?

Suppose that structure->key really works in the example below,
Code: [Select]
myfunction(mystruct_t *structure, struct_member *key, char *value)
{
   if (strncmp(desired_value_1,structure->key, size) == 0)
       {//do stuff}
what's supposed to happen if structure->key isn't actually a text but a float?

Maybe you can simply write your function like that:
Code: [Select]
myfunction(char *key, char *value, size_t len, char *somethingelse) {
 if (!strncmp(vaule, key, len)) {
  blah blah do something with somethingelse
 }
}

myfunction(&GPS_whatever.foo, "magic value", &GPS_whatever.bar);
It would probably take a bit of casting...

The thing is, C is not a dynamic language. It won't do typechecking at runtime for you. When you write code, you need to know which things will have which type in advance, or treat everything as char[] and then structures don't matter, just pass char* around.

Well, as of now it makes little differnce since the final goal is to convert them to json for sending to the server anyway.. So, a hacky workaround I have done is to define all the keys as char* ( I see that I have written this part wrong in the earlier post). All the keys are char*. That way the arguments are treated as such irrespective of the keys.. However, it would be nice to treat the data as its correct data type.

As you have mentioned.. it will be a problem with floats.. there is some sanitization / casting being done to ensure only a string is passed in as the "key" and the "value".

Quote from: magic
The thing is, C is not a dynamic language. It won't do typechecking at runtime for you. When you write code, you need to know which things will have which type in advance, or treat everything as char[] and then structures don't matter, just pass char* around.
I understand.. I am not trying to be cleverer than the people who have initially written the language nor the hundreds who have contributed to its development since.. :-) I have no doubt I ll fail miserably.. I am trying to make my code a little bit more robust and flexible at the same time. I know that sounds oxymoronic..
« Last Edit: July 21, 2020, 12:25:45 pm by krish2487 »
If god made us in his image,
and we are this stupid
then....
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4564
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: [C] - Passing a structure member as a parameter to a function
« Reply #24 on: July 21, 2020, 01:32:57 pm »
...

It looks self contained more or less.. AFAICS. However wouldnt that require that you need one such structure for every different type of data structures you are trying to maintain? And If I understand it right.. the same unions for setters and getters can also be extended for a char* type or boolean type.
Thank you for the suggestions though! :-)

PS: Yes, it is for device parameters / settings.. However, It is not just for device parameters.. I am also looking to generalize it for Self Test results and the payload to be sent to a server, once data is ready..
Yes, you would need one of those listItem entries per variable you need to access. Including getter/setter function. (the same thing you would need in c++)
Nothing limits you from referencing the same getter/setter function for multiple list entries, key is passed on. (you will need runtime key-type-location knowledge)
Yes, you can extend it to support char arrays, int arrays, or custom types. I have removed those from my example.
How you communicate with the above is a different layer. This part only provides a safe access method to any data via a public api.

Why would you even want a generic code to work with sturctures that have nothing in common with each other?
Code like this comes into play when you want to provide access to certain variables from your program from outside. In a layered and testable way.

For the above I wrote a metacompiler that assembles the items from troughout the code and creates one big consecutive list to link to the library.

But yes, true, you can get the same compiled result with a giant switch-case and a ton of global variables. However that is very manual and tightly coupled to layers tranceiving data.

Other things you may consider is ini files, json, or if you're brave, protobuf.
« Last Edit: July 21, 2020, 01:37:57 pm by Jeroen3 »
 
The following users thanked this post: krish2487


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf