Languages/C/SplitCH
From UIT
(Difference between revisions)
(→Source and header file split) |
Marc.pignat (Talk | contribs) (→Source and header file split) |
||
(22 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
{{TOC right}} | {{TOC right}} | ||
= Source and header file split = | = Source and header file split = | ||
− | |||
It is sometimes complicated to split the header and the source file, here are some hints: | It is sometimes complicated to split the header and the source file, here are some hints: | ||
+ | |||
+ | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [https://www.ietf.org/rfc/rfc2119.txt RFC 2119]. | ||
+ | |||
* (1) The header MUST contain what is necessary from the '''outside''' of the source file. | * (1) The header MUST contain what is necessary from the '''outside''' of the source file. | ||
* (2) The header SHOULD NOT contain, what is not necessary. | * (2) The header SHOULD NOT contain, what is not necessary. | ||
** There is no reason to pollute the namespace of the whole project. | ** There is no reason to pollute the namespace of the whole project. | ||
− | ** Keeping the interface small and as clean as possible will make team work | + | ** Keeping the interface small and as clean as possible will make team work simplier. |
− | * (3) The header file MUST prevent multiple inclusion | + | ** Including only the necessary headers will shorten (re-)compilation time. |
+ | * (3) The header file MUST prevent multiple inclusion, by using ''include guards''. | ||
* (4) A header file SHOULD be complete (it defines or includes all it needs). | * (4) A header file SHOULD be complete (it defines or includes all it needs). | ||
− | ** Example, if you use a uint32_t parameter in a function, the header should include <stdint.h> | + | ** Example, if you use a uint32_t parameter in a function, the header should include <stdint.h>. |
− | * (5) A header file SHOULD not include files only used in source file | + | ** This can be tested by compiling a empty C file only including the header. |
+ | * (5) A header file SHOULD not include files only used in source file. | ||
* (6) The header SHOULD be commented enough so there is no need to open the source file. | * (6) The header SHOULD be commented enough so there is no need to open the source file. | ||
− | * (7) The source file MUST include the header, preferably first | + | ** A consistent commenting SHOULD be used, for instance [http://www.doxygen.org doxygen] style. |
− | ** This will ensure consistency | + | * (7) The source file MUST include the header, preferably first. |
− | * (8) All symbols not exported by the header SHOULD be static (functions and variables) | + | ** This will ensure consistency and (4) |
− | ** | + | * (8) All symbols not exported by the header SHOULD be static (functions and variables). |
+ | ** This will prevent namespace pollution | ||
** Free benefit: the compiler can do better optimization (automatic inline, ...) | ** Free benefit: the compiler can do better optimization (automatic inline, ...) | ||
+ | * (9) C headers SHOULD be C++ friendly ("export C") | ||
+ | ** Without this C++ application can't link against C files | ||
+ | |||
== Temperature sensor example == | == Temperature sensor example == | ||
− | Here is a small example, using main.c, temp_sensor.h, and temp_sensor.c | + | Here is a small example, using <code>main.c</code>, <code>temp_sensor.h</code>, and <code>temp_sensor.c</code>. |
+ | |||
+ | * <code>temp_sensor.c</code> Contains the code for accessing a fictional temperature sensor. | ||
+ | * <code>temp_sensor.h</code> Defines the software interface for the temperature sensor. | ||
+ | * <code>main.c</code> Will display the current temperature. | ||
+ | |||
=== main.c === | === main.c === | ||
<source lang='c'> | <source lang='c'> | ||
− | |||
#include "temp_sensor.h" | #include "temp_sensor.h" | ||
+ | #include <stdio.h> | ||
int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||
{ | { | ||
− | + | printf("temperature is : %d", temp_sensor_get()); | |
+ | return 0; | ||
} | } | ||
</source> | </source> | ||
+ | |||
=== temp_sensor.h === | === temp_sensor.h === | ||
Line 39: | Line 54: | ||
* \brief Temperature sensor driver | * \brief Temperature sensor driver | ||
*/ | */ | ||
− | #ifndef TEMP_SENSOR_H // (3) prevent multiple inclusion, see the #endif at the end | + | #ifndef TEMP_SENSOR_H // (3) prevent multiple inclusion, see the #endif at the end of the file |
#define TEMP_SENSOR_H | #define TEMP_SENSOR_H | ||
+ | |||
+ | #ifdef __cplusplus // (9) C++ friendly export, see the corresponding closing brace | ||
+ | extern "C" { // This brace must contain every functions and variables declaration | ||
+ | #endif | ||
#include <stdint.h> // (4) We use stdint in the interface ! | #include <stdint.h> // (4) We use stdint in the interface ! | ||
Line 51: | Line 70: | ||
* \return the temperature in K. | * \return the temperature in K. | ||
* | * | ||
− | * \ | + | * \warning the value will be 0 if the sensor read fails. |
*/ | */ | ||
uint16_t temp_sensor_get(void); | uint16_t temp_sensor_get(void); | ||
+ | |||
+ | #ifdef __cplusplus | ||
+ | } | ||
+ | #endif | ||
#endif /* TEMP_SENSOR_H */ | #endif /* TEMP_SENSOR_H */ | ||
Line 68: | Line 91: | ||
#include "temp_sensor.h" // (7) Include the header for compile-time checks | #include "temp_sensor.h" // (7) Include the header for compile-time checks | ||
− | #include <super_os/i2c.h> // ( | + | #include <super_os/i2c.h> // (5) The i2c bus is not used in main, so it is included in this .c file, not in the .h |
// (2) These defines are private, we don't want to see them in main | // (2) These defines are private, we don't want to see them in main | ||
Line 85: | Line 108: | ||
static uint8_t read(uint8_t chip, uint8_t address, uint16_t *value) | static uint8_t read(uint8_t chip, uint8_t address, uint16_t *value) | ||
{ | { | ||
− | if (i2c_read( | + | if (i2c_read(chip, address, value, 2) != 0) |
{ | { | ||
− | return | + | return 1; |
} | } | ||
− | return | + | return 0; |
} | } | ||
Line 100: | Line 123: | ||
// Do what is said in temp_sensor.h | // Do what is said in temp_sensor.h | ||
− | if (status) | + | if (status != 0) |
{ | { | ||
temp = 0; | temp = 0; |
Latest revision as of 09:48, 31 March 2016
|
Source and header file split
It is sometimes complicated to split the header and the source file, here are some hints:
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
- (1) The header MUST contain what is necessary from the outside of the source file.
- (2) The header SHOULD NOT contain, what is not necessary.
- There is no reason to pollute the namespace of the whole project.
- Keeping the interface small and as clean as possible will make team work simplier.
- Including only the necessary headers will shorten (re-)compilation time.
- (3) The header file MUST prevent multiple inclusion, by using include guards.
- (4) A header file SHOULD be complete (it defines or includes all it needs).
- Example, if you use a uint32_t parameter in a function, the header should include <stdint.h>.
- This can be tested by compiling a empty C file only including the header.
- (5) A header file SHOULD not include files only used in source file.
- (6) The header SHOULD be commented enough so there is no need to open the source file.
- A consistent commenting SHOULD be used, for instance doxygen style.
- (7) The source file MUST include the header, preferably first.
- This will ensure consistency and (4)
- (8) All symbols not exported by the header SHOULD be static (functions and variables).
- This will prevent namespace pollution
- Free benefit: the compiler can do better optimization (automatic inline, ...)
- (9) C headers SHOULD be C++ friendly ("export C")
- Without this C++ application can't link against C files
Temperature sensor example
Here is a small example, using main.c
, temp_sensor.h
, and temp_sensor.c
.
-
temp_sensor.c
Contains the code for accessing a fictional temperature sensor. -
temp_sensor.h
Defines the software interface for the temperature sensor. -
main.c
Will display the current temperature.
main.c
#include "temp_sensor.h" #include <stdio.h> int main(int argc, char *argv[]) { printf("temperature is : %d", temp_sensor_get()); return 0; }
temp_sensor.h
/** * \file temp_sensor.h * * \brief Temperature sensor driver */ #ifndef TEMP_SENSOR_H // (3) prevent multiple inclusion, see the #endif at the end of the file #define TEMP_SENSOR_H #ifdef __cplusplus // (9) C++ friendly export, see the corresponding closing brace extern "C" { // This brace must contain every functions and variables declaration #endif #include <stdint.h> // (4) We use stdint in the interface ! // (6) Full comments, no need to open temp_sensor.c // (1) This function is needed in main /** * \brief Get the temperature * * \return the temperature in K. * * \warning the value will be 0 if the sensor read fails. */ uint16_t temp_sensor_get(void); #ifdef __cplusplus } #endif #endif /* TEMP_SENSOR_H */
temp_sensor.c
/** * \file temp_sensor.c * * \brief Temperature sensor driver implementation */ #include "temp_sensor.h" // (7) Include the header for compile-time checks #include <super_os/i2c.h> // (5) The i2c bus is not used in main, so it is included in this .c file, not in the .h // (2) These defines are private, we don't want to see them in main #define SENSOR_ADDRESS 0x12 #define SENSOR_REG 0x33 // (8) this function is not exported -> static // (6) this function MUST be commented here /** * \brief Do the real work here * \param chip, the i2c address of the chip * \param address, the address in the chip * \param value, where to store the value * \return 0 for no problem */ static uint8_t read(uint8_t chip, uint8_t address, uint16_t *value) { if (i2c_read(chip, address, value, 2) != 0) { return 1; } return 0; } // (6) This function is already commented in the header uint16_t temp_sensor_get(void) { uint16_t temp; uint8_t status = read(SENSOR_ADDRESS, SENSOR_REG, &temp); // Do what is said in temp_sensor.h if (status != 0) { temp = 0; } return temp; }