Function pointer with struct parameter inside struct - c

I have a struct which currently looks like this (abbreviated to show only the essential parts):
typedef struct {
uint32_t baudrate;
... some other internally used values here
void (*request_received)(void* hbus); //< this is what I'm talking about
} hbus_options_t;
This works. Basically it contains a function pointer which takes a pointer to a parameter of type void.
What I would actually like is for this to be easier to understand:
typedef struct {
uint32_t baudrate;
... some other internally used values here
void (*request_received)(hbus_options_t* hbus); //< this doesn't work
} hbus_options_t;
Obviously the compiler needs to know the struct before I can use it. How is this done usually? Using a void pointer works but it's harder to understand.

It's done by not being remiss and providing a struct tag:
typedef struct hbus_options {
uint32_t baudrate;
... some other internally used values here
void (*request_received)(struct hbus_options * hbus);
} hbus_options_t;
Besides readability, the compiler will also complain if you pass a pointer to something other than the intended struct type.
Adding a tag also allows for looser coupling of components. One can forward declare a structure, but not a type alias.

Related

Co-Dependent Definitions in C

Suppose we have a function pointer on a struct, which has the struct itself as the first argument, a typical callback scenario.
typedef void (*callback_type)(my_struct_type *mst, int whatever);
typedef struct {
// lots of fun stuff
callback_type notify_me;
} my_struct_type;
This produces a compiler error on the first typedef, as one might expect. error: unknown type name my_struct_type. Reversing the definitions produces the same result, but the unknown type is callback_type.
The easy solution is to do the following:
typedef struct my_struct_type_S {
// lots of fun stuff
void (*notify_me)(my_struct_type_S *mst, int whatever);
} my_struct_type;
However, doing this elides the function pointer type definition, which it would be nice to be able to easily refer to later, and use for static type checks, nice error messages, etc.
Any suggestions on how to resolve this?
Edit on "possible duplicate":
This scenario involves function pointer typedefs that are arcane to many people. I think this is a good example for that case, and additionally, the accepted answer is very clean, clear, and simple.
You can do this by giving the struct a tag and using a forward declaration of the struct. Then you can use the typedef for the function pointer, and subsequently complete the definition of the struct.
typedef struct my_struct_type_S my_struct_type;
typedef void (*callback_type)(my_struct_type *mst, int whatever);
struct my_struct_type_S {
// lots of fun stuff
callback_type notify_me;
};
You need to define the tag of the struct
typedef void (*callback_type)(struct _my_struct_type *mst, int whatever);
typedef struct _my_struct_type {
// lots of fun stuff
callback_type notify_me;
} my_struct_type;

Struct in function - differences

What is the proper way to passing struct into function?
Both solutions works fine, but is there any significant difference?
struct sensor
{
int32_t temperature;
}BME280;
int32_t read_temperature(struct sensor *BME)
{
}
vs
typedef struct sensor
{
int32_t temperature;
}BME2801;
int32_t read_temperature(BME2801 *BME)
{
}
int main(void)
{
BME2801 BME280;
}
In the first example, you are defining a structure of type struct sensor, and declaring a global variable called BME280 of the same type. Your read_temperature function is taking a pointer to a struct sensor. Your variable BME280 is not being used for anything.
In the second example, you are defining a structure of type struct sensor, and using typedef to create a new type name (BME2801), which will allow you to type BME2801 instead of struct sensor in your code. In your main function you are declaring a BME2801 (aka struct sensor) type variable with the name BME280. Your read_temperature function works the same, just as before.
These are two different examples and definitely not equivalent.
Your use of pointers to pass your structure by reference is good. Typically you want to pass all structures using pointers, especially if it is particularly big struct. Just cut out BME280 from your first example and you're golden.
Now comes the question of whether to use typedef to create a new type name to refer to a struct sensor. If it improves legibility and clarity, by all means do it. Assuming you want to refer to each struct sensor as BME2801, your second example does it correctly. I would argue that struct sensor is significantly clearer than BME2801 though. Usually you would define your structure in one of two ways and use it thusly:
struct sensor
{
int32_t temperature;
};
int32_t read_temperature (struct sensor *BME)
{
}
int main (void)
{
struct sensor BME280;
/* Initialize your struct with appropriate values here */
read_temperature (&BME280);
}
Or you can use typedef. This is typically done with structures to remove the requirement to use the keyword struct. C++ does this automatically without the explicit typedef.
typedef struct sensor
{
int32_t temperature;
}sensor;
/* 'sensor' now refers to the type 'struct sensor' */
int32_t read_temperature (sensor *BME)
{
}
int main (void)
{
sensor BME280;
/* Initialize your struct with appropriate values here */
read_temperature (&BME280);
}
Whether to typedef a struct to simply omit the struct keyword is a matter of style. The Linux kernel coding style suggests almost never using a typedef for structures unless you actively hiding its contents and encourage developers using your struct to use special accessor functions you provided. I follow this advice in my own code, but there are other opinions out there.

Passing struct as a parameter in place of void*

I have a function that accepts void* as parameter, but I want to use it as if it's a struct.
typedef struct struct1
{
int val;
} struct2;
void func1(void* struct3)
{
printf("%d",struct3->val);
}
My purpose is for example, if I have a .h file where the function is defined as
typedef void* parameter1;
void func1(parameter1 p1);
And I wants to use the struct as a parameter in that function, without declaring the struct in the .h file.
Thanks for the answer printf("%d",((struct2 *)struct3)->val) mentioned by #i486, that's what I was looking for.
In the header, declare the structure type as an incomplete type. For example:
typedef struct struct1 struct1;
extern void func1(struct1 *p1);
Or:
struct struct1;
void func1(struct struct1 *p1);
You can mix'n'match extern or not and typedef vs struct tag.
In the implementation code (or implementation header if you have multiple source files implementing the support for the type), you include the public header and define the structure type:
struct struct1
{
…private details…
};
In C11 and beyond, you can repeat a typedef as long as it refers to the same type; in earlier versions of C, you could not do that.
The advantage of this approach is that the client code is forced to use your functions because they don't know the internals of the structure, but they get a measure of type safety. In particular, a random structure pointer can't be passed to this function. If everything takes void *, then you can pass a wrong structure type to the function because all void pointers look alike. That's both unkind and unnecessary.

Why does "struct T* next" compile when T isn't an existing type?

I am using MinGW on Windows. I am building linked list and I am confused with this.
#include <stdio.h>
#include <stdlib.h>
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
int main(void)
{
List item;
List * head;
head = NULL;
return 0;
}
I now that struct can't have struct variable(object, instance of that struct), but can have pointer of that struct type. Didn't know that pointer can be pointer of unexisting type. struct BlaBla * next;(not for linked list, it must be struct Data * next but mean general talking)
Yes, you can, because then the compiler, upon encountering the unknown type name for the first time, assumes that there's somehwere a struct type definition with this name. Then it will forward-declare the struct name for you, let you use it as a pointer, but you can't dereference it nor can you do pointer arithmetic on it (since it's an incomplete type).
The compiler will accept code such as your example:
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
This is okay because the size of pointers is known to the compiler, and the compiler is assuming that the struct will be defined before it is dereferenced.
Because the compiler acts this way, it's possible to do this:
typedef struct Data
{
int x;
int y;
struct Data * next; /* points to itself */
} List;
However, if you were to include the struct inline, like this:
typedef struct Data
{
int x;
int y;
struct BlaBla blaStruct; /* Not a pointer. Won't compile. */
}List;
The compiler can't work out how big struct Data is because it doesn't know how big struct BlaBla is. To get this to compile, you need to include the definition of struct BlaBla.
Note that, as soon as you need to access the members of struct BlaBla, you will need to include the header file that defines it.
It depends on what you mean by "unexisting". If you haven't even declared BlaBla, you'll get an error.
If you've declared it but not yet defined it, that will work fine. You're allowed to have pointers to incomplete types.
In fact, that's the normal way of doing opaque pointers in C.
So, you might think that this is invalid because there's no declaration of struct BlaBla in scope:
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
However, it's actually okay since it's both declaring struct BlaBla and defining next at the same time.
Of course, since definition implies declaration, this is also okay:
struct BlaBla { int xyzzy; };
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
In order to declare a variable or field of a given type, pass one as a parameter, or copy one to another of the same type, the compiler has to know how many bytes the variable or field occupies, what alignment requirements it has (if any), and what other pointer types it's compatible with, but that's all the compiler needs to know about it. In all common dialects of C, a pointer to any structure will always be the same size and require the same alignment, regardless of the size of the structure to which it points or what that structure may contain, and pointers to any structure type are only compatible with other pointers to the same structure type.
Consequently, code which doesn't need to do anything with pointers to a structure except allocate space to hold the pointers themselves [as opposed to the structures at which they point], pass them as parameters, or copy them to other pointers, doesn't need to know anything about the structure type to which they point beyond its unique name. Code which needs to allocate space for a structure (as opposed to a pointer to one) or access any of its members must know more about its type, but code which doesn't do those things doesn't need such information.

Why often a struct's tagName differs from the typedef's name?

Sometimes I see code like this (I hope I remember it correctly):
typedef struct st {
int a; char b;
} *stp;
While the usual pattern that I familiar with, is:
typedef struct st {
int a; char b;
} st;
So what's the advantage in the first code example?
You probably mean this:
typedef struct ST {
/* fields omitted */
} *STP;
The asterisk is at the end of the statement. This simply means "define the type STP to be a pointer to a struct of this type". The struct tag (ST) is not needed, it's only useful if you want to be able to refer to the struct type by itself, later on.
You could also have both, like so:
typedef struct {
/* fields omitted */
} ST, *STP;
This would make it possible to use ST to refer to the struct type itself, and STP for pointers to ST.
Personally I find it a very bad practice to include the asterisk in typedefs, since it tries to encode something (the fact that the type is a pointer) into the name of the type, when C already provides its own mechanism (the asterisk) to show this. It makes it very confusing and breaks the symmetry of the asterisk, which appears both in declaration and use of pointers.
It's a habit that stems from the time when typedef names and struct tagnames were in the same namespace. See http://blogs.msdn.com/oldnewthing/archive/2008/03/26/8336829.aspx
I think you are talking about :
typedef struct{
int a;
char b;
} object, *objectPointer;
This means that (new) type objectPointer is a pointer to struct (object) defined above. Its easy to declare pointers to object struct this way. For instance,
objectPointer A = (objectPointer)malloc(sizeof(object));
A->a = 2;
Now, A is a pointer to struct object and you can access its variables as described above.
In case, objectPointer was not defined,
struct object *A = (struct object *)malloc(sizeof(object));
A->a = 2;
So, I guess objectPointer is more intuitive and easy to use.
I hope that the first code would say a compiler error ,
I see no good reason for the typedef name be different from the tag name.
Now, the reason for which the tag name needs to be typedefed if you don't want to use
struct tag v;
but
tag v;
is probably an historical one. For as long as I remember, C had typedef but I don't know if it was true when struct have been introduced (handling of typedef is a nuisance in the C grammar). In the old code I've seen, using typedef for struct isn't done, and there are things like unix
struct stat;
int stat(const char*, struct stat*);
which would break with an automatic typedef. One those are introduced, changing is quite difficult (yes, C++ has automatic typedef but C++ has special wording to handle that case of overloading and it would be yet another complication).

Resources