Generate compilation error in C for not using a function

3

A problem arose in creating a mini-library to simulate Threads in a PIC.

You would have to force the programmer to implement a function. I would like to know if there is any way to use the preprocessors inside functions and only call it if the function is used.

It would look something like this:

void teste(){
    #define _teste
}

int main(){
    teste();

    return 0;
 } 

 #ifndef _teste
     #error "Chame a funcao teste()"
 #endif

Is it possible to do this in any way?

Edit: How to return an informational error, in C, at compilation time due to lack of something necessary for the operation, such as initialization of a timer for example, that does not generate compile error?     

asked by anonymous 20.07.2018 / 19:57

1 answer

1

A typical C compiler has these steps, exactly in that order:

  • Preprocessing.
  • Lexical, syntactic and semantic analysis of the code.
  • Intermediate code generation (object code, these files with extension .o ).
  • Linkage.
  • Executable code generation.

Let's suppose you start with this in main.c :

void teste();

int main() {
    teste();
}

Notice the prototype of the teste() function there. It states that the function exists somewhere, and that it is the linker's responsibility to find it. If it does not find it, it will throw an error like this (assuming you are using GCC, but it will look something like some other compiler):

/home/blablabla/blablabla.o: In function 'main':
main.c:(.text.startup+0x7): undefined reference to 'teste'
collect2: error: ld returned 1 exit status

The error message says that the teste function could not be found. It could be declared in a different file ( teste.c for example):

#include <stdio.h>
void teste() {
    printf("foo");
}

And then, by compiling the two sources together, the linker will find the teste() function.

You can try to make the preprocessor work with this by making main look like this:

void teste();

int main() {
    teste();
}

#ifndef _teste
#   error Voce esqueceu de implementar o teste.
#endif

If the programmer does not set _teste anywhere, this error will appear. However, this solution is incomplete because there is no guarantee that the teste() function and the _teste symbol appear together. For example, verification is bypassed if no teste.c exists:

#define _teste
// Esqueci de implementar a função aqui!

Another one that goes wrong is this:

#include <stdio.h>
void teste() {
   printf("Foo");
}
// Esqueci de dar o #define _teste

In that case, the error persists even though the function has been implemented.

However, this does not work at all. The preprocessor processes the files separately, so even though the programmer places the teste() function and the _teste symbol on another file, the error will still be triggered.

You can try to remedy with #include in main.c :

#include "teste.inc"
void teste();

int main() {
    teste();
}

#ifndef _teste
#   error Voce esqueceu de implementar o teste.
#endif

And so, the programmer defines the function teste() and the symbol _teste within teste.inc . However, this is not good programming practice because header files (files with .h extension) should not have implementation. While in this case, you are not using the header file exactly as a header but rather abusing the header definition to import an implementation (so we use a different extension, .inc ).

The problem is that the preprocessor is just a tool for copy-and-paste text and in fact, it is a totally separate language from C. There is a language that is the one of the preprocessor and another completely different language that is the one of the compiler and both do not communicate except for the fact that the output of one is the input of the other. Therefore, it is not only possible in the preprocessor to know if the function was declared because the preprocessor does not even know what a function is and it sees its code just as a lot of text being blindly copied to the output . On the other hand, the linker (which is also separate from the compiler and the preprocessor except that it uses the compiler output as input) has nothing to do with custom error messages.

We can think of a different approach. You can already provide a skeleton for the teste function and abandon #ifdef . For example, if everything is done in a single source code:

#include <stdio.h>

void teste();

int main() {
    teste();
}

void teste() {
#   error Voce esqueceu de implementar o teste. Substitua essa mensagem pelo codigo.
}

In multiple source code, with the caveat that you are abusing the purpose of #include , you can do this in main.c :

#include "teste.inc"

void teste();

int main() {
    teste();
}

And no teste.inc :

#include <stdio.h>

void teste() {
#   error Voce esqueceu de implementar o teste. Substitua essa mensagem pelo codigo.
}
    
20.07.2018 / 20:46