Multiple Files (C/C++)
When the code to your robot becomes large enough, splitting it into multiple files can help structure your code and make it easier to find things.
Header vs. Source Files:
In C and C++, you'll commonly find source (implementation) files and header (API) files. Source files contain the actual functionality of your program, and header files define the functions, variables, etc. that are viewable by other files in the code.
Source files typically end .c
for C code, or .cpp
or .cxx
for C++ code.
Header files typically end with .h
for C and C++ code, or .hpp
or .hxx
for C++ code.
Typically, but not always, you'll find one header file per source file.
In Practice:
When using objects in the context of a header and source file, be sure to:
Declare your classes and functions in header files: Define the class structure, its data members, and function prototypes in a header file with a
.h
or.hpp
extension. The same applies for functions not associated with a class.In the header, be sure to use the extern keyword to declare that the motor, sensor, or other object is initialized somewhere else (see example below).
Implement your class methods in source files: Write the implementation of your class methods in a source file with a
.cpp
(for C++) or corresponding extension. This keeps your code organized and improves compile time. This is not necessary with built in objects such as motors and other sensors.
Other good practices:
Use
#include
guards in header files: To prevent multiple inclusions of the same header file, use#include
guards or#pragma once
at the beginning of your header files (more on this below).Include the necessary header files in source files: In your source file, include the header file of the class and any other headers necessary for the implementation with the
#include
directive.Separate interface from implementation: Keep the class interface in the header file clear and concise, focusing on what the class does. Leave the how to the source file where you implement the methods.
Header Guards
Its important to ensure that headers are only included once in each source file. This is done with header guards:
If header guards aren't present, it may lead to compilation issues when a header file is included multiple times either directly or indirectly through other headers. This can lead to multiple definitions of the same class, function, or variable, causing compilation errors due to redefinition. Additionally, omitting header guards can significantly increase compile times as the same header is processed multiple times.
Under the hood, what #include does is blanket copying and pasting the header file into where the include is. That's why the redefinition may occur.
Example Usage:
To summarize, source files can include a header file to make functions, variables, and other objects that were defined in another source file(such as a motor or a sensor) visible. It helps to keep code organized and readable.
In most project layouts (such as a pros project), the src directory is used for storing the .cpp files, while the inc directory is used for storing header files.
Bad Example Usage:
IncorrectMain.cpp
bad_example.hpp
bad_example.cpp
This code will result in a linker error because undefinedFunction()
is implemented in bad_example.cpp
but is not declared in bad_example.hpp
, so IncorrectMain.cpp
doesn't know about its existence.
Applications for Robotics
A common application for this is branching each of the subsystems into their own files rather than cramming all the subsystems into one.
This helps making organizing and navigating code a lot easier, as each subsystem is fit nicely into its own file.
Teams Contributed to this Article:
BLRS (Purdue SIGBots)
Last updated