Struct in function - differences - c

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.

Related

How to declare array of structs in C

I am having trouble declaring an array of structs prior to populating them with data.
My struct looks like this:
typedef struct {
uint8_t * p_data; ///< Pointer to the buffer holding the data.
uint8_t length; ///< Number of bytes to transfer.
uint8_t operation; ///< Device address combined with transfer direction.
uint8_t flags; ///< Transfer flags (see #ref NRF_TWI_MNGR_NO_STOP).
} nrf_twi_mngr_transfer_t;
And in my code I am trying to declare the array like this:
struct nrf_twi_mngr_transfer_t start_read_transfer[10];
However I get a compile error:
array type has incomplete element type 'struct nrf_twi_mngr_transfer_t'
I have searched around as I thought should be a common thing, but I can't figure out what I am doing wrong. Maybe because one of the elements is a pointer? But that pointer should be a fixed size right?
Many thanks
It looks like some explanations are in order. This code
typedef struct {
//...
} nrf_twi_mngr_transfer_t;
Already defines a type which can be used directly. In contrast,
struct nrf_twi_mngr_transfer_struct {
//...
};
Would define a struct name, and to access it you'd need to indicate that you are referring to a struct.
As a result, given two definitions above, you should define your arrays differently:
nrf_twi_mngr_transfer_t arr[10]; // if using typedef
struct nrf_twi_mngr_transfer_struct arr2[10]; // if using struct with no typedef
And just in case you are wondering,
struct {
//...
} nrf_twi_mngr_transfer_obj;
Defines an object of anonymous struct type.

Function pointer with struct parameter inside struct

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.

C structure multiple types

I'd like to write a library in C and I don't know what is the recommended way. I got for example structure and multiple functions like this:
typedef struct example
{
int *val;
struct example *next;
} Example;
and I have build function for multiple types of val
Example* build() { do sth };
Example* buildf() { do sth }; // val is float
Example* buildd() { do sth }; // val is double
What is the better practice (used in "professional" library). Use pointer to void and casting or have structure for all possibilities - int, float, double.
Use a union and some way to store type info:
typedef struct example
{
enum{ T_STRUCT_WITH_INT, T_STRUCT_WITH_FLOAT, T_SO_ON } type;
union {
int val_int;
float val_float;
} val;
struct example *next;
} Example;
Access fields after checking type by s->val.val_int
In C11 you can have union anonymous and fields can be accessed like s->val_int
This is primarily based on some combination of opinion, experience and the specific requirements at hand.
The following approach is possible, inspired by some container library work by Jacob Navia. I've never used it myself:
struct container_node {
struct container_node *link_here, *link_there, *link_elsewhere;
/*...*/
char data[0]; /* C90 style of "flexible array member" */
};
struct container_node *container_node_alloc(size_t data_size);
The allocation function allocates the node large enough so that data[0] through data[data_size-1] bytes of storage are available. Through another set of API functions, user data of arbitrary type be copied in and out.
The following approach is sometimes called "intrusive container". The container defines only a "base class" consisting of the link structure. The user must embed this structure into their own structure:
struct container_node {
struct container_node *next, *prev;
};
void container_insert(struct container *container, struct container_node *n);
struct container_node *container_first(struct container *container);
The user does this:
struct my_widget {
struct container_node container_links;
int widget_height;
/* ... */
};
/* .... */
/* We don't insert my_widget, but rather its links base. */
container_insert(&widg_container, &widget->container_links);
Some macros are used to convert between a pointer to the widget and a pointer to the container links. See the container_of macro used widely in the Linux kernel:
struct my_widget *wptr = container_of(container_first(&widg_container),
struct my_widget, container_links);
See this question.
Then there approaches of storing a union in each node, which provides an integer, floating-point-value or a pointer. In that case, the data is separately allocated (though not necessarily: if the caller controls the allocation of the nodes, it's still possible to put the node structure and the user data in a buffer that came from a single malloc call).
Finally, there are also approaches which wrap these techniques with preprocessor templating, an example of which are the BSD QUEUE macros.

Declaring a struct (that's already been typedef'd) within another struct?

My understanding of C is that there are two separate namespaces, one for tags (such as for structs) and one for all other variables (including structs). Using typedef before a struct definition will then treat the struct variable as a type, so if you use
struct car_part {/* Code Here */} CarPart;
(where CarPart is optional)
you'd have to use
struct car_part engine;
to declare a car part.
Whereas if you used a typedef with
typedef car_part {/* Code Here */} CarPart;
you can now use
CarPart engine;
instead.
typedef struct tag {/* Code here */} struct_name;
1) Is there any difference between declaring the actual variable before or after the block code? i.e.
typedef struct tag struct_name
{
/* Code here */
};
vs
typedef struct tag
{
/* Code here*/
} struct_name;
2) Are there ever any advantages to not using typedef for a struct definition, even if you won't declare another struct variable of that type?
3) The following code says that there's a syntax error C2061 with the identifier Node, but I don't see anything wrong with it. I tried adding the keyword struct before each element declaration, but that only gave more errors. Any thoughts?
typedef struct Ticket
{
char customer_name[20];
int ticket_number;
} Ticket;
typedef struct Node
{
Ticket ticket_info;
Node *next;
Node *previous;
} Node;
typedef struct Queue
{
Ticket *front;
Ticket *rear;
int queue_count;
} Queue;
edit: fixed first two lines of code to explicitly state where the element declarations should be.
There are actually four name-spaces in C (although this depends on a particular way of counting, and some include macro names as a fifth space, which I think is a valid way to think about them):
goto labels
tags (struct, union, and enum)
the actual members of a struct or union type (one per type, hence you could count this as "many" instead of "one" name space)
all other ("ordinary") identifiers, such as function and variable names and the names made to be synonyms for other types via typedef.
While it should (in theory) be possible to have separate spaces for struct vs union, for instance, C does not, so:
struct foo; union foo; /* ERROR */
is invalid. Yet:
struct foo { int a, b; };
struct bar { char b; double a; };
is just fine, showing that the members of the two different struct types are in different name-spaces (so again this makes the count of "4 name-spaces" above suspect :-) ).
All that aside, C has some moderately (and in some ways unnecessarily) complicated, but quite workable in practice, rules for how struct types work.
Each struct creates a new type unless it refers back to an existing type. The struct keyword may be followed by an identifier, or just an open brace {. If there is just an open brace, the struct creates a new type:
struct { ... } X; /* variable X has a unique type */
If there is an identifier, the compiler must look at the (single) tag name-space to see if that name is already defined. If not, the struct defines a new type:
struct blart { ... } X; /* variable X has type <struct newname>, a new type */
If the identifier is already present, generally this refers back to the existing type:
struct blart Y; /* variable Y has the same type as variable X */
There is one special exception, though. If you're in a new scope (such as at the beginning of a function), a "vacuous declaration"—the struct keyword, followed by an identifier, followed by a semicolon—"clears out" the previous visible type:
void func(void) {
struct blart; /* get rid of any existing "struct blart" */
struct blart { char *a; int b; } v;
Here v has a new type, even if struct blart was already defined outside func.
(This "vacuous declaration" trick is mostly useful in obfuscated code contests. :-) )
If you're not at a new scope, a vacuous declaration serves the purpose of declaring that the type exists. This is mainly useful to work around a different issue, which I will cover in a moment.
struct blart;
Here struct blart alerts you (and the compiler) that there is now a type named "struct blart". This type is merely declared, meaning that the struct type is "incomplete", if struct blart has not yet been defined. This type is defined (and "complete") if struct blart has been defined. So:
struct blart { double blartness; };
defines it, and then any earlier or later struct blarts refer to the same type.
Here's why this sort of declaration is useful. In C, any declaration of an identifier has scope. There are four possible scopes: "file", "block", "prototype", and "function". The last one (function scope) is exclusively for goto labels, so we can ignore it from here on. That leaves file, block, and prototype scopes. File scope is a technical term for what most people think of as "global", in contrast with "block scope" which is "local":
struct blart { double blartness } X; /* file scope */
void func(void) {
struct slart { int i; } v; /* block scope */
...
}
Here struct blart has file scope (as does "global" variable X), and struct slart has block scope (as does "local" variable v).
When the block ends, struct slart goes away. You can no longer refer to it by name; a later struct slart creates a new and different type, in exactly the same way that a later int v; creates a new v, and does not refer to the v within the block scope inside function func.
Alas, the committee that designed the original C standard included (for good reason) one more scope, inside the function prototype, in a way that interacts rather badly with these rules. If you write a function prototype:
void proto(char *name, int value);
the identifiers (name and value) disappear after the closing parenthesis, just as you'd expect—you wouldn't want this to create a block-scope variable called name. Unfortunately, the same happens with struct:
void proto2(struct ziggy *stardust);
The name stardust goes away, but so does struct ziggy. If struct ziggy did not appear earlier, that new, incomplete type that is created inside the prototype, has now been removed from all human reach. It can never be completed. Good C compilers print a warning here.
The solution is to declare the struct—whether complete or not [*]—before writing the prototype:
struct ziggy; /* hey compiler: "struct ziggy" has file scope */
void proto2(struct ziggy *stardust);
This time, struct ziggy has an already-existing, visible declaration to refer back to, so it uses the existing type.
[* In header files, for instance, you often don't know if the header that defines the struct has been included, but you can declare the struct yourself, and then define protoypes that use pointers to it.]
Now, as to typedef...
The typedef keyword is syntactically a storage-class specifier, like register and auto, but it acts quite weird. It sets a flag in the compiler that says: "change variable declarations into type-name aliases".
If you write:
typedef int TX, TY[3], *TZ;
the way that you (and the compiler) can understand this is to start by removing the typedef keyword. The result needs to be syntactically valid, and it is:
int TX, TY[3], *TZ;
This would declare three variables:
TX has type int
TY has type "array 3 of int"
TZ has type "pointer to int"
Now you (and the compiler) put the typedef back in, and change "has" to "is another name for":
TX is another name for type int
TY is another name for "array 3 of int"
TZ is another name for "pointer to int"
The typedef keyword works with struct types in exactly the same way. It's the struct keyword that creates the new type; then typedef changes the variable declaration(s) from "has type ..." to "is another name for type ...". So:
typedef struct ca ca_t;
starts by either creating new type, or referring back to existing type, struct ca as usual. Then, instead of declaring a variable ca_t as having type struct ca, it declares the name as another name for the type struct ca.
If you omit the struct tag name, you are left with only two valid syntactic patterns:
typedef struct; /* note: this is pointless */
or:
typedef struct { char *top_coat; int top_hat; } zz_t, *zz_p_t;
Here, struct { creates a new type (remember, we said this way back at the beginning!), and then after the closing }, the identifiers that would have declared variables, now make type-aliases. Again, the type was actually created by the struct keyword (although it hardly matters this time; the typedef-names are now the only ways to refer to the type).
(The reason the first pointless pattern is the way it is, is that without the braces, the first identifier you stick in is the struct-tag:
typedef struct tag; /* (still pointless) */
and thus you haven't omitted the tag after all!)
As for the last question, about the syntax error, the problem here is that C is designed as a "single pass" language, where you (and the compiler) never have to look very far forward to find out what something is. When you attempt something like this:
typedef struct list {
...
List *next; /* ERROR */
} List;
you've given the compiler too much to digest at once. It starts by (in effect) ignoring the typedef keyword except to set the flag that changes the way variables will be declared. This leaves you with:
struct list {
...
List *next; /* ERROR */
}
The name List is simply not yet available. The attempt to use List *next; does not work. Eventually the compiler would reach the "variable declaration" (and because the flag is set, change it to a type-alias instead), but it's too late by then; the error has already occurred.
The solution is the same as with function prototypes: you need a "forward declaration". The forward declaration will give you an incomplete type, until you finish defining the struct list part, but that's OK: C lets you use incomplete types in a number of positions, including when you want to declare a pointer, and including with typedef alias-creation. So:
typedef struct list List; /* incomplete type "struct list" */
struct list { /* begin completing "struct list" */
...
List *next; /* use incomplete "struct list", through the type-alias */
}; /* this "}" completes the type "struct list" */
This gains relatively little over just writing struct list everywhere (it saves a bit of typing, but so what? well, OK, some of us suffer a bit of carpal tunnel / RSI issues :-) ).
[Note: this last segment is going to cause controversy... it always does.]
In fact, if you mentally replace struct with type, C code becomes a whole lot nicer to "strongly typed language" fans. Instead of the terrible [%], weak-sauce:
typedef int distance; /* distance is measured in discrete units */
typedef double temperature; /* temperatures are fractional */
they can write:
#define TYPE struct
TYPE distance;
TYPE temperature;
These, being incomplete types, are truly opaque. To create or destroy or indeed do anything with a distance value you must call a function (and—for most variables anyway; there are some exceptions for external identifiers—use pointers, alas):
TYPE distance *x = new_distance(initial_value);
increase_distance(x, increment);
use_distance(x);
destroy_distance(x);
Nobody can write:
*x += 14; /* 3 inches in a dram, 14 ounces in a foot */
It simply won't compile.
Those who are a bit less bondage-and-discipline with their type systems can relax the constraints by completing the type:
TYPE distance { int v; };
TYPE temperature { double v; };
Of course, now "cheaters" can do:
TYPE distance x = { 0 };
x.v += 14; /* 735.5 watts in a horsepower */
(well, at least that last comment is correct).
[% Not really that terrible, I think. Some seem to disagree.]
1) The difference between those two blocks of code is that the first one is invalid syntax, while the second one is good and useful. I use the second one in order to define a struct and also define a typedef for the struct at the same time. My code has stuff that looks like this:
typedef struct Dog {
int age, barks;
} Dog;
After that line, I can define dogs with Dog mydog; or struct Dog mydog;.
It's important to understand that the code above is doing two things. It is defining a type named struct Dog, and then it is defining a type named Dog that just refers to struct Dog. You could split that into two separate steps like this:
struct Dog {
int age, barks;
};
typedef struct Dog Dog;
2) I always use the typedef as shown above in the first block of code and have found no problem with it. I would say there are no advantages to leaving out the typdef. Just for the record, if you want to leave out the typedef and only define a struct, then you code would be:
struct Dog {
int age, barks;
};
If you do it that way, you can only make new dogs by typing struct Dog mydog;; in other words, the name of the type is only struct Dog and Dog does not name a type.
3) The problem is that you are trying to use "Node" inside the definition of "Node". That would be a circular definition. You can fix everything by just writing it like this:
struct Node;
typedef struct Node
{
struct Node * next;
struct Node * previous;
} Node;
1) Your first example is invalid syntax. The correct way is this:
typedef struct tag {
/* ... */
} struct_name;
2) Using typedefs for structures makes them seem like atomic data types. It also allows for you to make the types opaque (so other code blocks can't see the inside of the structure). Personally, I find typedef-ing of structures to be a very bad habit (since the struct identifier helps differentiate structures and typedefs of atomic types).
3) You are trying to use the typedef'd version of the node structure inside itself! You need to use the struct Node identifier for the structure when defining it within itself. Like this:
typedef struct Node {
Ticket ticket_info;
struct Node *next;
struct Node *previous;
} Node;

Generic static Vector data type in C with data segment memory

Is it possible to create a generic Vector like data structure in C, with out using heap. Basically I need a array data type but a more generalized version on if it.
typedef struct {
/* some data types*/
}TYPE1;
typedef struct {
/* some data types*/
}TYPE2;
typedef struct _GCACHE_T
{
const int element_size;
const int count;
struct _ELEMENT {
UBYTE data[element_size];
BOOLEAN is_valid;
}element[count];
}GCACHE_T;
GCACHE_T f_cache1 = {sizeof(TYPE1), 15, {0} };
GCACHE_T f_cache2 = {sizeof(TYPE2), 10, {0} };
The above code will not compile but I have provided it for a better clarity on my requirement.
This would have been easy implemted provided heap memory was allowed to use. Since the code is meant for small micros heap memory usage is not allowed.
I could have used right away, but just checking if it can be done in a generic way.
TYPE1 f_cache1[15];
TYPE2 f_cache2[10];
The Vector will not grow in size. I could have also used a union but there is a memory trade off so not willing to use it.
Such parametric (template, generic) types are not supported by C. You can take an approach similar to the one used by the BSD socket subsystem. There different network addresses (e.g. IP address and TCP/UDP port number) are stored in structures of varying size (depending on the address family, e.g. IPv4 structures are shorter than IPv6 ones) but with similar layout in the beginning. Whenever an address is required, a pointer to the generic struct sockaddr type is passed instead and the correct structure type is inferred from the address family of the socket.
C supports the so-called flexible array members, but it cannot be simply applied to your case because not only is the number of struct _ELEMENT entries different, but the size of those elements could differ depending on the value of element_size. This makes it hard to compute the address of cache.element[i].data[j] in a portable way whithout refering to the actual type. What you can do is put an additional field in the beginning of the GCACHE_T type that helps you identify the true size of struct _ELEMENT:
typedef struct _GCACHE_T
{
int element_size;
int count;
size_t element_stride;
struct _ELEMENT {
BOOLEAN is_valid;
UBYTE data[];
} element[];
} GCACHE_T;
element_stride keeps the size of the concrete element type (including any padding). Note that is_valid is moved before data[] as C allows only the last element of a structure to be a flexible one.
You would then create specific types, e.g.
typedef struct _GCACHE_TYPE1_15_T
{
int element_size;
int count;
size_t element_stride;
struct {
BOOLEAN is_valid;
UBYTE data[sizeof(TYPE1)];
} element[15];
} GCACHE_TYPE1_15_T;
GCACHE_TYPE1_15_T f_cache1 = {
sizeof(TYPE1),
15,
// An awful hack to obtain the size of a structure member
sizeof(((GCACHE_TYPE1_15_T *)0)->element[0])
};
do_something((GCACHE_T *)&f_cache1);
Macros would come handy if you need to declare many different cache types. Now in do_something() you can compute the address of f_cache1.element[i].data[j] because you know the offset of the data field inside struct _ELEMENT and you can compute the offset of element[i] because the size of a single element is stored in the element_stride field.
Yeah, I know, it is a real pain... And I am not sure how much of the pointer arithmetic required works on a Harvard architecture device like PIC.

Resources