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.
Related
In the following code:
typedef struct
{
uint32_t variable_1;
}struct_1;
typedef struct
{
uint32_t variable_2;
}struct_2;
typedef struct
{
struct_1 struct_1_var;
struct_2 struct_2_var;
}struct_all;
struct_all variable_t[10];
struct_1* struct_1_var; //how to get this to point to an array of struct_1 that's inside variable_t?
Basically, I want to get an struct_1[10] or struct_2[10] that that is part of variable_t[10].
You can't, because there isn't an array of either struct_1s or struct_2s in variable_t to point to. There is an array of elements, each of which has a struct_1 and a struct_2.
If you want an array of just one type of the other of the values in variable_t, you'll need to copy them out one at a time into a new array.
Suppose I have a struct declaration in a header file like:
event.h
struct event_t;
and in the corresponding C file I would like to sort-of alias it with the Linux-specific struct inotify_event. The problem is that struct inotify_event contains flexible array member:
struct inotify_event {
int wd;
uint32_t mask;
uint32_t cookie;
uint32_t len;
char name[];
};
As per 6.7.2.1(p3) (emphasize mine):
A structure or union shall not contain a member with incomplete or
function type (hence, a structure shall not contain an instance of
itself, but may contain a pointer to an instance of itself), except
that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union
containing, possibly recursively, a member that is such a structure)
shall not be a member of a structure or an element of an array.
it is not possible to define the struct event_t as
struct event_t{
struct inotify_event base; //Non-conforming
};
So I could convert struct event_t * to struct inotify_event *. Since the 6.7.2.1(p3) concerns only about structs the solution I see is to redeclare the tag name as
union event_t
and then define it later as a single element union.
union event_t{
struct inotify_event event; //Conforming?
};
The only requirement the Standard imposes on union that I found is that the set of members of a union must be non-empty 6.2.5(p20) (emphasize mine):
A union type describes an overlapping nonempty set of member objects,
each of which has an optionally specified name and possibly distinct
type.
QUESTION: Is it a conforming/common way to hide an implementation details of some specific data structure through union?
This is how I would do it:
event.h
struct event_t;
event_t *create_event(void);
void free_event(event_t *ev);
event.c
#include "event.h";
event_t *create_event(void)
{
inotify_event *iev = ...;
return (event_t *)iev;
}
void free_event(event_t *ev)
{
inotify_event *iev = (inotify_event *)ev;
// free the event
}
However, if you want to store additional data with the event then:
event.h
struct event_t;
event_t *create_event(void);
void free_event(event_t *ev);
event.c
#include "event.h";
struct event_t
{
inotify_event *iev;
// additional data
};
event_t *create_event(void)
{
inotify_event *iev = ...;
event_t *ev = malloc(sizeof(event_t));
ev.iev = iev;
return ev;
}
void free_event(event_t *ev)
{
inotify_event *iev = (inotify_event *)ev.iev;
// free the event (iev) first
free(ev);
}
If you have multiple implementations that you need to hide in event_t then:
enum event_type
{
EVENT_TYPE_INOTIFY,
EVENT_TYPE_INOTIFY2,
};
struct event_t
{
event_type type;
union {
inotify_event *iev; // you use this when type == EVENT_TYPE_INOTIFY
inotify_event2 *iev2; // you use this when type == EVENT_TYPE_INOTIFY2
}
// additional data
};
By far the simplest technique is to put this into your event.h header:
typedef struct inotify_event event_t;
This declares that there is a structure type struct inotify_event and declares an alias for it event_t. But it does not define the content of struct inotify_event at all.
Only the implementation code in event.c includes the definition of struct inotify_event from the system header; everything else does not include that header and cannot access the elements of an event_t except through the accessor API you define.
You can enforce this separation of duties by code review — or by checking with grep, or other similar techniques — to ensure that no code except the implementation of your event type uses the system header for inotify_event. And, if you port to a system other than Linux without support for inotify, then you simply provide an alternative opaque structure type in place of struct inotify_event in your event.h header.
This avoids all questions about whether there are flexible array members within structures, etc; it is all a non-issue.
Note the Q&A about What does a type followed by _t (underscore t) represent? . Be cautious about creating your own types with the _t suffix ¸— consider using a prefix on such type names that gives you a chance that your names will be distinct from those provided by the system.
Single element union makes no sense. The purpose of union is to serve as a kind of polymorphic struct. struct members are accessed by offset, this is why is impossible to put an incomplete struct or array in the middle of a struct.
For example
struct foo { int a; int b[]; int c; };
In this example is impossible for the compiler to determine the address of c because b size can vary at runtime. But if you put incomplete array at the end all struct members address can be determined by the address of the start of the struct. Keep in mind that pointers are just address, so you can have any pointers to any structs and all the offsets can be determined, but you will need to deal with extra alloc/free stuff.
When you create an union you telling to compiler Hey! I have this members, reserve enough space for me so that I can treat this variable as foo or bar. In another words, the compiler will take the largest union member and this will be the size of the union. A common use for union is for representing multiple kinds of values.
typedef union { int integer, float real, char *string } value_type;
This way you can treat value_type as int, float, or a char pointer. You're code need to know the how to treat each member but the compiler will make sure that when you do malloc(sizeof value_type) you have enough space for the tree types.
Now your problem. You want to hide implementation details. Usually this is done by declaring a type or struct incompletely in a header, and completely only on your object files. Because of this when the user include your header all the information that the compiler has is struct my_struct;. It can't tell the size of my_struct so is impossible for you to allocate it as malloc(sizeof struct my_struct). Also since the user hasn't the member definitions it can't mess up with the struct internals.
Working like this you will need to provide user with functions for allocating and freeing my_struct, for example struct my_struct *foo = my_struct_new() and my_struct_destroy(foo).
You're already doing this. To deal with the struct inotify problem I would do one of these.
(1) Surround OS specific with #ifdef for that OS, so that the event_t has only the right members defined depending on the operating system. You will need #ifdef on your functions. This has the advantage to keep useless code out of final binary, so smaller footprint.
(2) Have pointers to OS specific structs and let runtime decide what to do. This easier to maintain.
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.
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.
Is it possible to make an array of declared but not defined types? This is what I would like to do:
typedef struct _indiv indiv;
typedef indiv pop[];
and let somebody else decide what an individual's members actually are by defining the struct _indiv in another .c or .h file (and then linking everything together).
(For the semantics, indiv is an individual and pop is a population of individuals.)
But the compiler complains:
error: array type has incomplete element type
I could replace the second typedef by
typedef indiv * pop;
And use pop like an array by accessing the elements like p[i] (with p of type pop), but if I do that the compiler will complain that
error: invalid use of undefined type ‘struct _indiv’
error: dereferencing pointer to incomplete type
I suppose since typedef struct _indiv indiv is only a declaration, the compiler does not know at compile time (before the linkage) how much space the struct requires and that it doesn't like it, thus forbiding to do what I'm trying. But I would like to know why and if there is a possible way to acheive what I want.
Thanks
If you want this source file to manipulate items of type indiv, then you have 2 choices.
1) Declare the structure, but don't define it. Use only pointers to the structure. Never dereference them:
struct _indiv;
typedef struct _indiv indiv;
typedef indiv * pop;
//sizeof(_indiv) is not known, how many bytes should we allocate?
pop p = malloc(N*unknownSize);
//this line will fail because it does not know how many bits to copy.
p[0] = getIndiv();
2) define the complete structure:
struct _indiv
{
int id;
char* name;
/*...*/
};
typedef struct _indiv indiv;
typedef indiv * pop;
pop p = malloc(N*sizeof(indiv));
//Now this line can work.
p[0] = getIndiv();
The suggestion to define a dummy 'indiv' is a bad one:
--- file1.c
struct _indiv
{
char dummy;
};
typedef struct _indiv indiv;
typedef indiv * pop;
pop p = malloc(N*sizeof(indiv)); //this will allocate N bytes.
//This will generate code that copies one byte of data.
p[0] = getIndiv();
---realIndiv.c
typedef struct _indiv
{
int id;
char* name;
/*...*/
} indiv;
indiv getIndiv();
{
indiv i = /* whatever */;
return i; //this will return 8+ bytes.
}
When you do this, the first file will be manipulating a differently sized item than the "real" indiv struct, and you are sure to get unexpected behaviour.
You are right that the compiler doesn't know the size of incomplete types (in your example, struct _indiv is an incomplete type), which is why you cannot declare a variable of such a type. This includes creating an array of such types.
However, this doesn't really matter, because if you don't have the complete definition of the type, then you can't sensibly access its members anyway: if you write p[i].foo, how do you know if the type actually has a member called foo, and if it does, what type it is?
If you want the struct type's members to be defined in another .c file (this is known as an "opaque type"), then you must only ever create and handle pointers to the struct. Your other .c should contain all the code that actually accesses the struct itself. The file that has only the incomplete type would contain code like:
indiv *i1, *i2;
i1 = new_individual("foo"); /* Create an individual */
i2 = new_individual("bar");
print_individual(i1);
...and the source file with the complete definition of the struct would contain the implementation of new_individual(), print_individual() and so on.
Under this scheme, the easiest way to deal with a population is to make it an array of pointers to indiv structs.
You can only define array of pointers to an undefined type, because you don't know size of that type.
Note that in C language you can define the same struct differently in many places. You can use this technique: Simply define your struct anyhow, then you can freely define and use pointers to that type. And then define the real struct with the same name somewhere else. Also you get the same effect when you simply use arrays of void*.