passing array of variables to function in C - c

I have a C function which needs a large amount of variables to be passed, so I came to the idea of "packing" them all in a single array (matrix of variables). The point is, these variables are of a very different type, some int, some arrays (strings and vectors), and many of them float. Is there a way to leave unspecified the type of data stored into the matrix? (I unsuccessfully explored the void "data type")

The elements of an array are always of a single type, that's the point.
Collecting variables of multiple types is the job for a structure, i.e. a struct.
This is a quite common way to solve this particular problem. If the structure becomes large, you might find it convenient to pass a pointer to an instance of it, rather than copying the entire thing in the call.

You can use va_list but struct is the best way to do it

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
enum type {
INT,
FLOAT,
PCHAR,
};
struct any_type {
enum type type_;
union {
int int_;
float float_;
char* pchar_;
};
};
#define MYSIZE 10
void process(size_t size, struct any_type* array)
{
for(int i = 0; i < size; i++) {
switch(array[i].type_) {
case INT :
printf("INT: %d\n", array[i].int_);
break;
case FLOAT :
printf("FLOAT: %f\n", array[i].float_);
break;
case PCHAR :
printf("PCHAR: %s\n", array[i].pchar_);
break;
default:
printf("UNKNOWN TYPE PROVIDED\n");
break;
}
}
}
int main(int argc, char *argv[])
{
struct any_type *array;
array = malloc(MYSIZE*(sizeof(struct any_type)));
array[0].type_ = INT;
array[0].int_ = 10;
array[1].type_ = FLOAT;
array[1].float_ = 2.5;
array[2].type_ = PCHAR;
array[2].pchar_ = "hello char";
process(3, array);
return 0;
}
You can extend type and union as needed. However using nameless unions require -std=c11.

Expanding on my comment above:
Needing to pass a large number of parameters1 to a function can be a sign that there is a problem in your design - your function may be trying to do too many things at once, and you would be better off refactoring it into several smaller functions, each of which only takes a subset of the parameters.
Assuming that's not the case, how are your parameters logically related to each other? Can they be considered attributes of a single data item? For example, a person may be described by the following attributes: surname, given name, birth date, sex. These can be collected together into a single struct type such as
#include <time.h>
struct person {
char *surname;
char *name;
struct tm birthdate; // struct tm defined in time.h
char sex;
};
void write_to( struct person *p )
{
p->surname = strdup( "McGillicuddy" );
p->name = strdup( "Aloysius" );
p->sex = 'M';
p->birthdate.tm_year = 32; // tm_year starts at 1900, so this is 1932
p->birthdate.tm_mon = 11; // december
p->birthdate.tm_day = 1;
};
int main( void )
{
struct person p;
...
write_to( &p );
...
}
Note that members of struct types can themselves be struct types - struct tm is a type defined in time.h that specifies a datetime value using multiple attributes.
Some notes on syntax:
When you want to access a member of a struct instance, use the . operator. When you want to access a member of a struct through a pointer, use the -> operator. In the function write_to, p is a pointer to struct person, so to access each member of p we use ->. The birthdate member is an instance of struct tm, not a pointer, so we use the . operator to access each member of birthdate.
p->m is equivalent to (*p).m.
Like I said in my comment, you should not collect otherwise unrelated items into a struct type just to reduce the number of parameters being passed to a function. They should all be attributes of a more complex type. Some other examples of what I mean:
// A node in a list
struct node {
data_t data; // for some data type data_t;
struct node *next;
struct node *prev;
};
// A street address
struct addr {
char *number; // to handle things like 102A, 102B
char *street;
char *city;
char state[3];
char *zip;
};
It's possible that you're really passing only a couple of distinct data items to your function, each of which is composed of a lot of different attributes. Take a step back and look at your variables and see how they relate to each other.
"Large" depends on context, and of course there are always exceptions to any rule, but in general passing more than 7 distinct, unrelated parameters is a sign you may need to refactor your function into several smaller functions.

Related

Pass a string in a struct to a function and return it

I want to return the name of the smallest city population-wise, if it is the second city. (Please don't mind the if statement, I know it's bland), the missing return is what bothers me.
I assume I should declare a pointer inside the function rSmallestCity, like *rtrn but I guess the source variable is destroyed before it is used?
typedef struct Coordinate{
int x,y;
}Coordinate;
typedef struct city{
char name[20];
int population;
Coordinate coordinates;
}city;
char *rSmallestCity(city **cl, int n)
{
char *rtrn = NULL;
if(cl[n-2]->population>cl[n-1]->population)
{
rtrn = &cl[n-1]->name;
}
return rtrn;
}
int main()
{
city c1 ={.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4};
city c2 ={.name="Delhi", .population=300, .coordinates.x=3, .coordinates.y=2};
city *clist[2];
clist[0]=&c1;
clist[1]=&c2;
printf("\n%s is smallest\n",rSmallestCity(clist,2));
}
warning: assignment to 'char ' from incompatible pointer type 'char ()[20]' [-Wincompatible-pointer-types]|
I assume I should declare a pointer inside the function rSmallestCity, like *rtrn but I guess the source variable is destroyed before it is used?
A good question. And your assumption is correct. Creating a variable inside a function it's existence ends upon leaving the function. But in this case, because the struct member name is already a char * you do not need to create another variable. Just return c1.name. (see code example below.)
A few other suggestions:
In the struct declaration:
typedef struct Coordinate{
int x,y;
}Coordinate;
You've used the same symbol (Coordinate) for the struct name, and for it's typedef. This is not a good practice. If you need both a struct name and a typedef, pick different symbols. BTW, in this this example, only one or the other is needed. Say you pick the typedef, then the struct is completely defined by:
typedef struct {
int x,y;
}Coordinate;
That suggestion applies to both struct declarations in your example code.
The signatures for the main function do not include int main(){...} rather
int main(void){..., return 0;} and int main(int argc, char *argv[]){..., return 0;}
The following code example illustrates some of the other suggestions for improvements in comments under your post,
typedef struct {
int x,y;
}Coordinate;
typedef struct {
char name[20];
int population;
Coordinate coordinates;
}city;
//return char * rather than char to allow for full null terminated char array (string)
char * rSmallestCity(city c1[],int cityCount)//generisize function prototype to
{ //to easily accommodate bigger arrays if needed
long long size, sizeKeep = 8e9; //index and population. initialize larger than possible population
int indexKeep = 0;
//note you do not need to define a char *, the struct already contains one
for(int i=0; i<cityCount; i++)//use a loop rather than a single comparison, keep the smalles
{
size = c1[i].population;
sizeKeep = (size < sizeKeep) ? indexKeep = i, size : sizeKeep;
}
printf("\n%s\n",c1[indexKeep].name);
return c1[indexKeep].name;
};
int main(void)//use minimum signature for main, and call return before leaving.
{
//combining your original declarations and assignments for struct
//into a single declaration/definition.
city c1[] = {{.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4},
{.name="Delhi", .population=300, .coordinates.x=3, .coordinates.y=2}};
int cityCount = sizeof(c1)/sizeof(c1[0]);
printf("\n%s is smallest",rSmallestCity(c1, cityCount));
return 0;
};
The solution that I originally left in comment under OP (remove & in the line &cl[n-1]->name;) needs some explanations to avoid problems later.
(It is an educational answer not a full answer on pointers, array decay, ... And many examples can be found on stackoverflow. I tried to simplify)
Try this simple code.
int main()
{
char myString1[25]="Toulouse" ; // French City
printf("%p\n",myString1);
printf("%p\n",&myString1);
}
The output is the same, but an array name and the address of an array name are not the same. The array name is evaluated to the address of its first element. So it works in your case but a warning is issued during compilation and it is very important. Firstly, do not remove compilation warnings.
Now, try this code :
int main()
{
char myString1[25]="Toulouse" ; // French City
printf("%p\n",myString1+1);
printf("%p\n",&myString1+1);
}
The outputs are different. Because myString1 is evaluated to char* and &myString1 to char [25]. So +1, in the first, case adds one (sizeof char) to the pointer and in the other case, it adds 25.
Delete the "&" in the line:
rtrn = &cl[n-1]->name;
To extremely simplify, you assigned an "address of char[]" to a char*, but array syntax makes it work regardless.

How do I hide some fields of struct in C?

I'm trying to implement a struct person, and I need to hide some fields or make them constant.
A trick for create private fields.
Header:
#pragma once
#define NAME_MAX_LEN 20
typedef struct _person {
float wage;
int groupid;
} Person;
const char const *getName (Person *p);
int getId (Person *p);
/// OTHER FUNCTIONS
Source
#include "person.h"
struct _person
{
int id;
float wage;
int groupid;
char name[NAME_MAX_LEN];
};
/// FUNCTIONS
GCC says that person.c:7:8: error: redefinition a 'struct _person' struct _person
I can write this in a header, but after it, I can't use fields of a struct.
typedef struct _person Person;
A struct cannot have multiple conflicting definitions. As such, you can't create a struct that hides some of the fields.
What you can do however it declare that the struct exists in the header without defining it. Then the caller is restricted to using only a pointer to the struct and using functions in your implementation to modify it.
For example, you could define your header as follows:
typedef struct _person Person;
Person *init(const char *name, int id, float wage, int groupid);
const char *getName (const Person *p);
int getId (const Person *p);
float getWage (const Person *p);
int getGroupid (const Person *p);
And your implementation would contain:
#include "person.h"
struct _person
{
int id;
float wage;
int groupid;
char name[NAME_MAX_LEN];
};
Person *init(const char *name, int id, float wage, int groupid)
{
Person *p = malloc(sizeof *p);
strcpy(p->name, name);
p->id = id;
p->wage= wage;
p->groupid= groupid;
return p;
}
...
C has no mechanism for hiding individual members of a structure type. However, by operating only in terms of pointers to such a type, and not providing a definition, you can make the whole type opaque. Users would then have to use the functions you provide to manipulate instances in any way. This is a thing that is sometimes done.
To some extent, you may be able to achieve something like what you describe with a hidden context. For example, consider this:
header.h
typedef struct _person {
float wage;
int groupid;
} Person;
implementation.c
struct _person_real {
Person person; // must be first, and is a structure, not a pointer.
int id;
char name[NAME_MAX_LEN];
};
Now you can do this:
Person *create_person(char name[]) {
struct _person_real *pr = malloc(sizeof(*pr));
if (pr) {
pr->person.wage = DEFAULT_WAGE;
pr->person.groupid = DEFAULT_GROUPID;
pr->id = generate_id();
strncpy(pr->name, name, sizeof(pr->name));
pr->name[sizeof(pr->name) - 1] = '\0';
return &pr->person; // <-- NOTE WELL
} else {
return NULL;
}
}
A pointer to the first member of a structure always points also to the whole structure, too, so if the client passes a pointer obtained from that function back to you, you can
struct _person_real *pr = (struct _person_real *) Person_pointer;
and work on the members from the larger context.
Be well aware, however, that such a scheme is risky. Nothing prevents a user from creating a Person without the larger context, and passing a pointer to it to a function that expects the context object to be present. There are other issues.
Overall, C APIs generally either take the opaque structure approach or just carefully document what clients are permitted to do with the data they have access to, or even just document how everything works, so that users can make their own choices. These, especially the latter, are well aligned with overall C approaches and idioms -- C does not hold your hand, or protect you from doing harm. It trusts you to know what you're doing, and to do only what you intend to do.
You can use a mixin style; e.g. write in the header:
struct person {
float wage;
int groupid;
};
struct person *person_new(void);
char const *getName (struct person const *p);
int getId (struct person const *p);
and in the source
struct person_impl {
struct person p;
char name[NAME_MAX_LEN];
int id;
}
struct person *person_new(void)
{
struct person_impl *p;
p = malloc(sizeof *p);
...
return &p->p;
}
chra const *getName(struct person const *p_)
{
struct person_impl *p =
container_of(p_, struct person_impl, p);
return p->name;
}
See e.g. https://en.wikipedia.org/wiki/Offsetof for details of container_of().
Addendum to John Bollinger's answer:
Although, IMHO, opaque pointer types with accessor functions (init/get/set/destroy) are the most secure approach, there's another option that allows users to place objects on the stack.
It's possible to allocate a single "typeless" chunk of memory as part of the struct and use that memory explicitly (bit by bit / byte by byte) instead of using additional types.
i.e.:
// public
typedef struct {
float wage;
int groupid;
/* explanation: 1 for ID and NAME_MAX_LEN + 1 bytes for name... */
unsigned long private__[1 + ((NAME_MAX_LEN + 1 + (sizeof(long) - 1)) / sizeof(long))];
} person_s;
// in .c file (private)
#define PERSON_ID(p) ((p)->private__[0])
#define PERSON_NAME(p) ((char*)((p)->private__ + 1))
This is a very strong indicator that access to the data in the private__ member should be avoided. Developers that don't have access to the implementation file won't even know what's in there.
Having said that, the best approach is an opaque type, as you may have encountered when using the pthread_t API (POSIX).
typedef struct person_s person_s;
person_s * person_new(const char * name, size_t len);
const char * person_name(const person_s * person);
float person_wage_get(const person_s * person);
void person_wage_set(person_s * person, float wage);
// ...
void person_free(person_s * person);
Notes:
avoid typedef with a pointer. It only confuses developers.
It's better to keep pointers explicit, so all developers can know that the type they're using is dynamically allocated.
EDIT: Also, by avoiding "typedefing" a pointer type, the API promises that future / alternative implementations will also use a pointer in it's API, allowing developers to trust and rely on this behavior (see comments).
When using an opaque type, the NAME_MAX_LEN could be avoided, allowing names of arbitrary length (assuming renaming requires a new object). This is an extra incentive to prefer the opaque pointer approach.
avoid placing the _ at the beginning of an identifier when possible (i.e., _name). Names starting with _ are assumed to have a special meaning and some are reserved. The same goes for types ending with _t (reserved by POSIX).
Notice how I use the _s to mark the type as a struct, I don't use _t (which is reserved).
C is more often snake_case (at least historically). The best known APIs and most of the C standard is snake_case (except where things were imported from C++).
Also, being consistent is better. Using CamelCase (or smallCamelCase) in some cases while using snake_case for other things could be confusing when developers try to memorize your API.
What John Bollinger wrote is a neat way of utilising how structs and memory works, but it's also an easy way to get a segfault (imagine allocating an array of Person and then later passing the last element to a 'method' which accesses the id or it's name), or corrupt your data (in an array of Person the next Person is overwriting 'private' variables of the previous Person). You'd have to remember that you must create an array of pointers to Person instead of array of Person (sounds pretty obvious until you decide to optimise something and think that you can allocate and initialise the struct more efficiently than the initialiser function).
Don't get me wrong, it's a great way to solve the problem, but you've got to be careful when using it.
What I'd suggest (though using 4/8 bytes more memory per Person) is to create a struct Person which has a pointer to another struct which is only defined in the .c file and holds the private data. That way it'd be harder to make a mistake somewhere (and if it's a bigger project then trust me - you'll do it sooner or later).
.h file:
#pragma once
#define NAME_MAX_LEN 20
typedef struct _person {
float wage;
int groupid;
_personPriv *const priv;
} Person;
void personInit(Person *p, const char *name);
Person* personNew(const char *name);
const char const *getName (Person *p);
int getId (Person *p);
.c file:
typedef struct {
int id;
char name[NAME_MAX_LEN];
} _personPriv;
const char const *getName (Person *p) {
return p->priv->name;
}
int getId (Person *p) {
return p->priv->id;
}
_personPriv* _personPrivNew(const char *name) {
_personPriv *ret = memcpy(
malloc(sizeof(*ret->priv)),
&(_personPriv) {
.id = generateId();
},
sizeof(*ret->priv)
);
// if(strlen(name) >= NAME_MAX_LEN) {
// raise an error or something?
// return NULL;
// }
strncpy(ret->name, name, strlen(name));
return ret;
}
void personInit(Person *p, const char *name) {
if(p == NULL)
return;
p->priv = memcpy(
malloc(sizeof(*p->priv)),
&(_personPriv) {
.id = generateId();
},
sizeof(*p->priv)
);
ret->priv = _personPrivNew(name);
if(ret->priv == NULL) {
// raise an error or something
}
}
Person* personNew(const char *name) {
Person *ret = malloc(sizeof(*ret));
ret->priv = _personPrivNew(name);
if(ret->priv == NULL) {
free(ret);
return NULL;
}
return ret;
}
Side note: this version can be implemented so that private block is allocated right after/before the 'public' part of the struct to improve locality. Just allocate sizeof(Person) + sizeof(_personPriv) and initialise one part as Person and second one as _personPriv.

C generic type as function argument input

So I have two different structs in which all the properties that I will be accessing will be the same. and I also have a function, who's argument, i want to be able to accept either of the two. Example:
typedef struct{
int whatnot = 14;
int thing[11];
} TH_CONFIG;
typedef struct{
int whatnot = 3;
int thing[5];
} TH_CONFIG_2;
*_CONFIG var;
void fun(*_CONFIG input)
{
input.whatnot = 5;
}
int main(){
fun(var);
}
I may have an inkling that I should use void as the type from that I could typecast or something?, but my searching has only yielded things about function pointers, templates, and C#.
EDIT: *_CONFIG is not meant to be syntactically correct, its signifying that I don't know what to do there, but its supposed to be the _CONFIG type
Possible solutions.
Just use an array of length 11 for both of them. Did you really run out of those last 6 bytes on your OS?
Make it a dynamic array.
Just write in assembly, you clearly don't care about C's higher-level-ness.
Use a language like C++ that supports templates or polymorphism.
Just pass in the arguments of the struct you care about.
void fun(int* whatnot) {
*whatnot = 5;
}
int main() {
fun(&myStruct.whatnot);
return 0;
}
Factor into a quasi-OO design.
struct {
int whatnot;
} typedef Common;
struct TH_CONFIG_1 {
Common common;
int thing[11];
};
struct TH_CONFIG_2 {
Common common;
int thing[5];
}
But if you insist...
void fun(void* input) {
( (int)(*input) ) = 5;
}
or...
void fun(void* input) {
( (TH_CONFIG*) input)->whatnot = 5; // may have been a TH_CONFIG_2, but who cares?
}
Note: this would not pass code review at any C shop.
You can use any pointer type and cast it.
If all the properties you're accessing are the same, I'm guessing one's an extension of the other (since the properties need to have the same offset from the beginning of the struct). In that case you may want to use this pattern:
struct base {
int foo;
char **strings;
};
struct extended {
struct base super;
double other_stuff;
};
Since super is at the start of struct extended, you can cast a struct extended * to struct base * without problems. Of course, you could do that by repeating the same fields in the beginning of struct extended instead, but then you're repeating yourself.

typecheck for return value

I have a list in which i want to be able to put different types. I have a function that returns the current value at index:
void *list_index(const List * list, int index) {
assert(index < list->size);
return list->data[index];
}
In the array there are multiple types, for example:
typedef struct structA { List *x; char *y; List *z; } structA;
typedef struct structB { List *u; char *w; } structB;
Now in order to get data from the array:
structA *A;
structB *B;
for(j=0... ) {
A = list_index(list, j);
B = list_index(list, j);
}
But now how do I find out the type of the return value? Is this possible with typeof (I'm using GCC btw)?
And is this even possible or do i have to make some sort of different construction?
You'll have to use unions like shown here.
The best way to solve this would be to use unions.
Another way would be to memcpy() the list item to an actual struct (i.e., not a pointer) of the appropriate type. This would have the advantage of making each List item as small as possible.
A third way would be to just cast the pointer types as in type punning. C allows this as long as the object is dereferenced with its either its correct type or char.
Either way, you will need to put a code in each structure that identifies the type of object. There is no way the compiler can figure out what a pointer points to for you. And even if you could use typeof, you shouldn't. It's not C99.
Technically, if you don't use a union, you will have a problem making a legal C99 access to the type code, because you will need to make a temporary assumption about the type and this will violate the rule that objects must be dereferenced as their actual type, via a union, or via a char *. However, since the type code must by necessity be in the same position in every type (in order to be useful) this common technical violation of the standard will not actually cause an aliasing optimization error in practice.
Actually, if you make the type code a char, make it the first thing in the struct, and access it via a char *, I think you will end up with code that is a bit confusing to read but is perfectly conforming C99.
Here is an example, this passes gcc -Wall -Wextra
#include <stdio.h>
#include <stdlib.h>
struct A {
char typeCode;
int something;
};
struct B {
char typeCode;
double somethingElse;
};
void *getMysteryList();
int main()
{
void **list = getMysteryList();
int i;
for (i = 0; i < 2; ++i)
switch (*(char *) list[i]) {
case 'A':
printf("%d\n", ((struct A *) list[i])->something);
break;
case 'B':
printf("%7.3f\n", ((struct B *) list[i])->somethingElse);
break;
}
return 0;
}
void *getMysteryList()
{
void **v = malloc(sizeof(void *) * 2);
struct A *a = malloc(sizeof(struct A));
struct B *b = malloc(sizeof(struct B));
a->typeCode = 'A';
a->something = 789;
b->typeCode = 'B';
b->somethingElse = 123.456;
v[0] = a;
v[1] = b;
return v;
}
C handles types and typing entirely at compile time (no dynamic typing), so once you've cast a pointer to a 'void *' its lost any information about the original type. You can cast it back to the original type, but you need to know what that is through some other method.
The usual way to do this is with some kind of type tag or descriptor in the beginning of all the objects that might be stored in your list type. eg:
typedef struct structA { int tag; List *x; char *y; List *z; } structA;
typedef struct structB { int tag; List *u; char *w; } structB;
enum tags { structAtype, structBtype };
You need to ensure that every time you create a structA or a structB, you set the tag field properly. Then, you can cast the void * you get back from list_index to an int * and use that to read the tag.
void *elem = list_index(list, index)
switch (*(int *)elem) {
case structAtype:
/* elem is a structA */
:
case structBtype:
/* elem is a structB */
Make the elements you want to put into the list all inherit from a common base class. Then you can have your base class contain members that identify the actual type.
class base {
public:
typedef enum {
type1,
type2,
type3
} realtype;
virtual realtype whatAmI()=0;
};
class type_one : public base {
public:
virtual base::realtype whatAmI() { return base::type1; };
};
class type_two : public base {
public:
virtual base::realtype whatAmI() { return base::type2; };
};
After that, you'd declare your list type like:
std::list<base *> mylist;
and you can stuff pointers to any of the derived types into the list. Then when you take them out, you can just call 'whatAmI()' to find out what to cast it to.
Please note: Trying to do this in C++ means you are doing something in a way that's not a good match for C++. Any time you deliberately evade the C++ type system like this, it means you're giving up most of the usefulness of C++ (static type checking), and generally means you're creating large amounts of work for yourself later on, not only as you debug the first iteration of this app, but especially at maintenance time.
You have some choices. Keep in mind that C is basically not a dynamically typed language.
You Make a common base for the structs, and put a simple type indicator of your own in it.
struct base {
int type_indication:
};
then
struct structA {
struct base base;
...
};
and then you can cast the pointer to (struct base *).

Is there any way to pass a structure type to a c function

I have some code with multiple functions very similar to each other to look up an item in a list based on the contents of one field in a structure. The only difference between the functions is the type of the structure that the look up is occurring in. If I could pass in the type, I could remove all the code duplication.
I also noticed that there is some mutex locking happening in these functions as well, so I think I might leave them alone...
If you ensure that the field is placed in the same place in each such structure, you can simply cast a pointer to get at the field. This technique is used in lots of low level system libraries e.g. BSD sockets.
struct person {
int index;
};
struct clown {
int index;
char *hat;
};
/* we're not going to define a firetruck here */
struct firetruck;
struct fireman {
int index;
struct firetruck *truck;
};
int getindexof(struct person *who)
{
return who->index;
}
int main(int argc, char *argv[])
{
struct fireman sam;
/* somehow sam gets initialised */
sam.index = 5;
int index = getindexof((struct person *) &sam);
printf("Sam's index is %d\n", index);
return 0;
}
You lose type safety by doing this, but it's a valuable technique.
[ I have now actually tested the above code and fixed the various minor errors. It's much easier when you have a compiler. ]
Since structures are nothing more than predefined blocks of memory, you can do this. You could pass a void * to the structure, and an integer or something to define the type.
From there, the safest thing to do would be to recast the void * into a pointer of the appropriate type before accessing the data.
You'll need to be very, very careful, as you lose type-safety when you cast to a void * and you can likely end up with a difficult to debug runtime error when doing something like this.
I think you should look at the C standard functions qsort() and bsearch() for inspiration. These are general purpose code to sort arrays and to search for data in a pre-sorted array. They work on any type of data structure - but you pass them a pointer to a helper function that does the comparisons. The helper function knows the details of the structure, and therefore does the comparison correctly.
In fact, since you are wanting to do searches, it may be that all you need is bsearch(), though if you are building the data structures on the fly, you may decide you need a different structure than a sorted list. (You can use sorted lists -- it just tends to slow things down compared with, say, a heap. However, you'd need a general heap_search() function, and a heap_insert() function, to do the job properly, and such functions are not standardized in C. Searching the web shows such functions exist - not by that name; just do not try "c heap search" since it is assumed you meant "cheap search" and you get tons of junk!)
If the ID field you test is part of a common initial sequence of fields shared by all the structs, then using a union guarantees that the access will work:
#include <stdio.h>
typedef struct
{
int id;
int junk1;
} Foo;
typedef struct
{
int id;
long junk2;
} Bar;
typedef union
{
struct
{
int id;
} common;
Foo foo;
Bar bar;
} U;
int matches(const U *candidate, int wanted)
{
return candidate->common.id == wanted;
}
int main(void)
{
Foo f = { 23, 0 };
Bar b = { 42, 0 };
U fu;
U bu;
fu.foo = f;
bu.bar = b;
puts(matches(&fu, 23) ? "true" : "false");
puts(matches(&bu, 42) ? "true" : "false");
return 0;
}
If you're unlucky, and the field appears at different offsets in the various structs, you can add an offset parameter to your function. Then, offsetof and a wrapper macro simulate what the OP asked for - passing the type of struct at the call site:
#include <stddef.h>
#include <stdio.h>
typedef struct
{
int id;
int junk1;
} Foo;
typedef struct
{
int junk2;
int id;
} Bar;
int matches(const void* candidate, size_t idOffset, int wanted)
{
return *(int*)((const unsigned char*)candidate + idOffset) == wanted;
}
#define MATCHES(type, candidate, wanted) matches(candidate, offsetof(type, id), wanted)
int main(void)
{
Foo f = { 23, 0 };
Bar b = { 0, 42 };
puts(MATCHES(Foo, &f, 23) ? "true" : "false");
puts(MATCHES(Bar, &b, 42) ? "true" : "false");
return 0;
}
One way to do this is to have a type field as the first byte of the structure. Your receiving function looks at this byte and then casts the pointer to the correct type based on what it discovers. Another approach is to pass the type information as a separate parameter to each function that needs it.
You can do this with a parameterized macro but most coding policies will frown on that.
#include
#define getfield(s, name) ((s).name)
typedef struct{
int x;
}Bob;
typedef struct{
int y;
}Fred;
int main(int argc, char**argv){
Bob b;
b.x=6;
Fred f;
f.y=7;
printf("%d, %d\n", getfield(b, x), getfield(f, y));
}
Short answer: no. You can, however, create your own method for doing so, i.e. providing a specification for how to create such a struct. However, it's generally not necessary and is not worth the effort; just pass by reference. (callFuncWithInputThenOutput(input, &struct.output);)
I'm a little rusty on c, but try using a void* pointer as the variable type in the function parameter. Then pass the address of the structure to the function, and then use it he way that you would.
void foo(void* obj);
void main()
{
struct bla obj;
...
foo(&obj);
...
}
void foo(void* obj)
{
printf(obj -> x, "%s")
}

Resources