Structures
Overview
Structures (also called structs) is a way in C to group several related variables into a larger variable. They are also supported in C++, although classes are normally used instead (one of the key differences between the two in C++ is that struct members are public by default, classes members are private by default).
Basic Usage
For example, the following code declares a struct
that represents an error, and encapsulates an errorCode
and an errorString
:
struct error {
uint8_t errorCode;
char * errorString;
};
This only declares the struct, to use one we must create an instance of it. Then members can be accessed with the dot (.
) operator:
int main() {
struct error myError;
myError.errorCode = 4;
myError.errorString = "User error";
}
Using Typedef
The typedef
keyword can be used when defining a struct
:
typedef struct {
uint8_t errorCode;
char * errorString;
} error_t;
And then instead of creating an instance with struct error <variable_name>
, you can use error_t <variable_name>
like so:
int main() {
error_t myError;
myError.errorCode = 4;
myError.errorString = "User error";
}
Initialising Structures
Initialising structures is way of defining what the values of the variables inside the struct
will be at the time of creation. Note that there is a big syntax difference between initialising structures in C and in C++.
// Defining a structure type
typedef struct
{
uint16_t value1;
uint16_t value2;
} demoStruct_t;
// Creating a structure and initialising the variables
// Note that this is won't work in C++
demoStruct_t struct1 =
{
.value1 = 560;
.value2 = 34;
}
Unfortunately, you cannot define default variables for a structure when you declare it, only when you create an instance of that structure type. If this is annoying you, you might want to consider switching to C++, which allows you to do such a thing by using the class and constructor mechanisms.
Copying Structures
You can easily copy a struct
in C with the assignment operator (=
). Although not the recommended method, you can also use memcpy()
to do the same thing.
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
typedef struct {
uint16_t value1;
uint16_t value2;
} demoStruct_t;
int main(void) {
demoStruct_t struct1;
demoStruct_t struct2;
// Copy using assignment (recommended way)
struct2 = struct1;
// Copy using memcpy()
memcpy(&struct2, &struct1, sizeof(struct2));
return 0;
}
Be careful, as passing in a struct
to a function will copy the entire structure, which is some cases might NOT be what you were expecting as:
- For a large struct, this could result in a lot of memory on the stack being used up.
- Any changes the function makes to the struct will not be seen from the calling function.
In these cases you what to pass in a pointer to the struct
instead.
Self-referencing Structures
You can self-reference a structure, but you cannot include the structure type in the structure itself (with would cause infinite recursion). To self-reference a structure, you have to use the little-used (in C anyway) name after typedef struct.
typedef struct cmd_t {
// This is a legal self-reference
cmd_t* cmdPtr;
} cmd_t;
typedef struct cmd_t {
// This is an illegal infinite recursion error
cmd_t cmd;
} cmd_t;
// This following declaration has got the first cmd_t
// missing. This will cause an cmd_t is undefined error.
typedef struct {
cmd_t cmd;
} cmd_t
Further Reading
Structs are a key part of the opaque pointer design pattern.