Home > Mobile >  Forcing at most once inclusion in embedded C
Forcing at most once inclusion in embedded C

Time:10-19

I am working on an embedded system, written in ANSI C. For what its worth, it's a Pic32MX/MZ (we have systems on both), though it shouldn't be relevant. I also cannot make use of C or Rust.

I have written code to control a peripheral. I want to allow only 1 other file to reference this peripheral.

So imagine I have:

perihperal1.h peripheral1.c my_file1.c myfile2.c

Is there any way to ensure only 1 of my_file1.c or myfile2.c can have #include perihperal1.h?

I cannot find a way to force it in code, and would prefer forcing it, instead of relying just on good discipline.

Edit:

The purpose of this is some that I can separate the hardware initialization code from the business logic that may interact with said peripheral.

I want to avoid setting up a UART, and including it somewhere, and then having it also included elsewhere. It can be done with proper discipline, but in a large team errors do often occur.

CodePudding user response:

If there is any legitimate reason for doing such, you could do something like this:

a.h:

int unique_include_a = 1;

a.c:

#include "a.h"

int a()
{
  return 123;
}

int main()
{
  a();
  return 0;
}

b.c:

#include "a.h"

int b()
{
  return 456;
}

Compile and link:

gcc a.c b.c

The linker should issue an error:

/usr/bin/ld: /tmp/ccmC6JPZ.o:(.data 0x0): multiple definition of `unique_include_a'; /tmp/ccjvwQrZ.o:(.data 0x0): first defined here
collect2: error: ld returned 1 exit status
    

CodePudding user response:

The proper solution is to document the UART code. Along the lines of "NOTE: this is a singleton implementation. It may only be called from a single code module in the project."

It is also possible to include run-time guards against such attempts as well. Suppose you have uart_init which must be executed first in order to use the driver. You can then implement it as:

uart_result_t uart_init (/* params */)
{
  static bool initialized=false;
  if(initialized)
  {
    return UART_ERR_MULTIPLE_CALLS; // some error code
  }
  initialized=true;
  ...
}

This adds a minimum of run-time overhead and attempting to do multiple calls will get spotted early on during development.


That is, unless you wish the code to handle multiple identical UART peripherals on the same MCU, then you need to implement it differently. For example as an opaque type that flags the specified UART peripheral as taken and returns an error like in the above example.

  • Related