I am writing embedded C code for a microcontroller. The code has to be shared between three different circuit boards, and the input/output configurations are set at run time from some tables during initialization.
The microcontroller has 24 ADC channels, and I have a function that can either set or clear a pin as an ADC channel. This means that an input to the function can consist of 0 to 23 (which is set in the table) and nothing else.
I would like to put some kind of preprocessor or compiler "thing" that could identify that the function received a value other than 0-23 and throw some kind of error or warning and prevent the code from compiling in case someone put an invalid value in the table.
Does anyone have some advice on how best to do this?
In computing, compile-time function execution (or compile time function evaluation, or general constant expressions) is the ability of a compiler, that would normally compile a function to machine code and execute it at run time, to execute the function at compile time.
Compile-time checking occurs during the compile time. Compile time errors are error occurred due to typing mistake, if we do not follow the proper syntax and semantics of any programming language then compile time errors are thrown by the compiler.
Compile time is the period when the programming code (such as C#, Java, C, Python) is converted to the machine code (i.e. binary code). Runtime is the period of time when a program is running and generally occurs after compile time.
Absolute code is generated when it is known at compile time where the process resides in memory.
On most compilers (preprocessors) you can use the #error
directive.
I.e.
#define ADC_CHANNEL 34
#if ADC_CHANNEL > 23
#error ADC_CHANNEL exceeds maximum allowed value
#endif
The above would throw an error, and would not compile.
Then use ADC_CHANNEL as the input to your function.
Or you can make ADC_CHANNEL
an enum
, and define ADC_CHANNEL_0 = 0
, ADC_CHANNEL_1 = 1
... ADC_CHANNEL_23 = 23
. Then make your function take type ADC_CHANNEL_t
, or whatever you want to call it, and that way if the function is called using the enumerated type as the argument, there will be no way to use an out-of-bounds value.
Example:
typedef enum {ADC_CHANNEL_0 = 0,
ADC_CHANNEL_1 = 1,
ADC_CHANNEL_2 = 2,
// ...etc...
ADC_CHANNEL_22 = 22,
ADC_CHANNEL_23 = 23} adc_channel_t;
void setClearAdcPin(adc_channel_t adcChannel) {
// ...function body...
}
(You don't technically need the = 0
, = 1
, etc., since the compiler will infer that from the order. By default enum
s start at 0 and increment by 1 for each value. But defining each value manually is safer, and lets you do things like only include the 3 possible ADC channels that you might possibly use, even if they aren't consecutive.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With