Compiler warning about missing preprocessor symbol [duplicate] - c

This question already has answers here:
C macro to enable and disable code features
(6 answers)
Closed 7 years ago.
Background
I have C project which has a configuration header file, for example:
// config.h
#define FEATURE_1_AVAILABLE 1
#define FEATURE_2_AVAILABLE 0
#define FEATURE_3_AVAILABLE 1
Modules use these flags to include/exclude features from build:
#include "config.h"
void foo(void) {
...
#if FEATURE_1_AVAILABLE
useFeature1();
#endif
...
There are different versions of config.h for different builds.
Problem
#include "config.h" got accidentally removed, so feature wasn't active even when it was enabled in config.
Unfortunately #if FEATURE_1_AVAILABLE silently evaluates to 0 when it's not defined. So I need an error if it's not defined.
Option 1
I could add extra 'if defined' test on each condition.
#ifndef FEATURE_1_AVAILABLE
#error No feature 1
#elif FEATURE_1_AVAILABLE
useFeature1();
#endif
Downside is that one feature flag may be tested in many different places in module, and adding multiple preprocessor lines is not going to make code prettier.
Option 2
Add single test at the beginning of the module:
#ifndef FEATURE_1_AVAILABLE
#error No feature 1
#endif
But this can be lost/forgotten for the same reasons that #include "config.h" was.
Option 3
Define flags as macros:
#define FEATURE_1_AVAILABLE() 1
and use as:
#if FEATURE_1_AVAILABLE()
Unfortunaltely this will also fail silently, if you forget the parenthesis:
#if FEATURE_1_AVAILABLE
Option X
Is there a better option? Something that will give error message at compile time if symbol is not defined or is incorrectly written. And hopefully doesn't make code look unmaintainable preprocessor mess.
Other things
Runtime checks are not possible. Disabled features must not be in the binary.
Features must be defined in file. Defining them as global compiler options has other problems.
This for embedded system. Some of these features require hardware to work, and testing is very time consuming. So having errors at compile time is preferred.

Another solution is to have the compiler warn you if a macro being evaluated is not defined.
With gcc for example there is the -Wundef option (not included in -Wall):
#if FEATURE_1_AVAILABLE
useFeature1();
#endif
this gives the warning (add -Werror to make it an error):
tst.c:6:9: warning: "FEATURE_1_AVAILABLE" is not defined [-Wundef]
#if FEATURE_1_AVAILABLE
This option is also available with other compilers, e. g., clang and icc.

I know it is being frowned upon, but for smaller C projects there is nothing wrong with having one project-wide include file (say myproject.h) with all your #include .. directives (like #include "config.h") , and then have only #include "myproject.h at the top of each source file.
Accidentally forgetting this single #include will usually break the compile immediately, so that won't happen unnoticed.
Alternatively, you could put one essential #include (say #include assert.h) in your config.h (and only there), again to annoy the compiler/linker when you forget to include it

Related

Using macros with the same name in different header files

I use macros like #DEBUG to print some additional debugging info and even possibly do something differently to help me with debugging. For example:
in header a.h:
#define DEBUG 1
in src a.c:
#include "a.h"
int func_a () {
/*some code*/
#if DEBUG
//do this
#endif
}
What will happen if I use a macro with the same name in another file ?
header b.h
#define DEBUG 1
#if DEBUG
# define PRINT 1
#elif
#define PRINT 0
#endif
src b.c
#include "a.h"
#include "b.h"
int func_b () {
/*some code*/
#if PRINT
//do this
#endif
/*some code*/
#if DEBUG
//do this
#endif
}
What will happen if I change the value of #DEBUG in one of the headers? I saw in some other answers that redefining a macro is not allowed in the C standard. But when I compile with GCC using the -Wall flag I see no errors or warnings.
What will happen if I use a macro with the same name in another file ?
It depends. C does not allow an identifier that is already defined as a macro name at some point in a translation unit to be defined again at that point, unless the redefinition specifies an identical replacement list. This is a language constraint, so conforming implementations will emit a diagnostic about violations they perceive. Compilers may reject code that contains violations, and if they nevertheless accept such code then the resulting behavior is undefined as far as C is concerned.
In practice, implementations that do accept such violations have two reasonable choices (and a universe of unreasonable ones):
ignore the redefinition, or
process the redefinition as if it were proceeded by an #undefine directive specifying the affected macro name.
Implementations of which I am aware accept such redefinitions and implement the latter option, at least by default.
If your headers are defining macros solely for their own internal use then you may be able to address the issue by exercising some discipline:
Each header puts all its #include directives at the beginning, before any definition of the possibly-conflicting macro(s).
Each header #undefines the possibly-conflicting macro at the end, under all conditional-compilation scenarios in which the macro may be defined in the first place.
On the other hand, if the macro is intended to be referenced by files that use the header(s) where it is defined then undefining it within the header would defeat the purpose. Under some circumstances, probably including yours, you can address that by defining the macro only conditionally in each header:
#if !defined(DEBUG)
#define DEBUG 1
#endif
That will avoid redefinition, instead using (only) the first definition encountered, which may even come from compiler command-line arguments. If you do this, however, it is essential that all the default definitions specified in that way be the same, else changing your headers' inclusion order will have unexpected effects code that depends on which definition is used.

Adding a code to be compiled in lex first

I'm looking for a way to insert an #undef to the lex generated source code that will appear before the built in lines lex generates.
When compiling a file.l with lex, I generate a lex.yy.c file. In my file.l I have written :
#include "y.tab.h"
#undef __STRICT_ANSI__
#include <string.h>
The #undef helps me compile the code under the flag -std=c99 So it needs to be done before including string.h. But the generated file includes string.h before copying my undef.
Without the #undef I am getting a lot of warnings due to the use of strdup. I have seen the normal fixes using flags, but like I said I can't access the makefile.
Adding 'manually' the line
#undef __STRICT_ANSI__
into lex.yy.c before fixes everything. But i prefer not to touch any of the generated code and have it done by lex.
I have read this,
strdup(): Confused about warnings ('implicit declaration', 'makes pointer...without a cast', memory leak)
And like i said it does solve it.
But only if I can somehow force the generated file to run the undef first.
To start with, #undef __STRICT_ASCII__ is not the correct way to enable the declaration of Posix functions like strdup.
Posix extensions which are declared in standard C library header files are made conditional on "feature test macros". You can read a summary in man feature_test_macros but in any case, the documentation for any function which requires a feature test macro includes a description of which macros are required. In the case of strdup, we can read in man strdup:
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
strdup():
_XOPEN_SOURCE >= 500
(Followed by more possibilities.)
Personally, I always use
#define _XOPEN_SOURCE 700
which requests declarations for all functions in the latest version of Posix.
One way to insert the feature test macro before any include of a standard library function is to do so on the compile command line:
-D_XOPEN_SOURCE=700
I like doing it this way, because I can add it to my Makefile and then it applies to every compilation (which is basically what I want). Usually, makefiles include a feature which allows you to add this option to your compiler flags without modifying the file. For example, the following will often work:
make file CPPFLAGS="-D_XOPEN_SOURCE=700"
(CPPFLAGS is a common makefile variable used to set preprocessor flags.)
But if you want to put it into your flex file, you can use a %top block:
%top {
#define _XOPEN_SOURCE 700
}
%top is like %{ but it puts the inserted code right at the beginning of the generated code.
If nothing else works, you can always just insert the declaration for strdup, (also taken from man strdup) into your flex prologue.
%{
char *strdup(const char *s);
#include "y.tab.h"
%}
Both the C standard and the Posix standard allow explicit declaration of library functions (but not macros) as an alternative to including relevant headers.

What is the scope of a #define?

What is the scope of a #define?
I have a question regarding the scope of a #define for C/C++ and am trying to bet understand the preprocessor.
Let's say I have a project containing multiple source and header files. Let's say I have a header file that has the following:
// header_file.h
#ifndef __HEADER_FILE
#define __HEADER_FILE
#define CONSTANT_1 1
#define CONSTANT_2 2
#endif
Let's then say I have two source files that are compiled in the following order:
// source1.c
#include header_file.h
void funct1(void)
{
int var = CONSTANT_1;
}
// source2.c
#include header_file.h
void funct2(void)
{
int var = CONSTANT_2;
}
Assuming I have included all the other necessary overhead, this code should compile fine. However, I'm curious as to what #defines are remembered between compilations. When I compile the above code, are the contents of each #include actually included, or are the include guards actually implemented?
TLDR: Do #defines carry over from one compilation unit to the next? Or do #define only exist within a single compilation unit?
As I type this out, I believe I'm answering my own question and I will state my believed answer. #defines are constrained to a single compilation unit (.c). The preprocessor essentially forgets any #defines when it goes from one compilation unit to the next. Thus in the above example I listed, the include guards do not come into play. Am I correct in this belief?
source1.c is compiled separately from source2.c therefore your defines are processed for source1 as it is compiled and then as an independent action they are processed for source2 as it is compiled.
Hopefully this is a clear explanation.
Preprocessor macros do not have "scope" as such, they just define a piece of text that should replace the macro in the code.
This means that the compiler never sees the strings CONSTANT_1 and CONSTANT_2 but instead gets the source in a preprocessed form with these macros replaced with their expansions (1 and 2 respectively).
You may inspect this preprocessed source by calling gcc with the -E flag, or with whatever flag only does preprocessing on your particular compiler.
Yes, you are right!!
Compilation of a file, in it self, is merely, just a process under execution. One process can not interfare with another unless explicitly done. The c pre-processors are just literal substitution mechanism, performed in a dumb way. Whatever conditional checking are performed, are confined to ongoing instance of pre-processor only, nothing gets carry forward once execution (compilation) comes to end. Pre-processors do not "configure" compiler, their scope is limited till "their own compilation"

#include guards does not work and #pragma once is obsolete

There are two head files _stub_defs.h
///stub code
#pragma once
#include "random.h"
#include <stdarg.h>
and stasrg.h
#ifndef __GNUC_VA_LIST
#define __GNUC_VA_LIST
typedef __builtin_va_list __gnuc_va_list;
#endif
When I use my cross-compiler(sparc-rtems-gcc) to compile, the two head files both are included.Then the terminal tells me:
warning: #pragma once is obsolete
stdarg.h: conflicting types for `__gnuc_va_list'
stdarg.h: previous declaration of `__gnuc_va_list'
Obviously, #include guards does not work.Is this the problem of head files' codes or the problem of my cross-compiler?
The include guards work. You have another problem.
The best way to debug this is to run only the C preprocessor. For gcc (including cross compiler gcc), you can use the -E option. Just add this to your compile stage. Instead of getting an object file, you will get a C file after the preprocessor stage.
Take that file, and search for the duplicate definition there. The file will also have markers that tell the compiler which file this definition originally came from, as well as markers when includes are nested. If you follow those, you will see both where the two definitions come from and which file included each of them.

How do you include a header file that may or may not exist?

Let's assume I define BAR in foo.h. But foo.h might not exist. How do I include it, without the compiler complaining at me?
#include "foo.h"
#ifndef BAR
#define BAR 1
#endif
int main()
{
return BAR;
}
Therefore, if BAR was defined as 2 in foo.h, then the program would return 2 if foo.h exists and 1 if foo.h does not exist.
In general, you'll need to do something external to do this - e.g. by doing something like playing around with the search path (as suggested in the comments) and providing an empty foo.h as a fallback, or wrapping the #include inside a #ifdef HAS_FOO_H...#endif and setting HAS_FOO_H by a compiler switch (-DHAS_FOO_H for gcc/clang etc.).
If you know that you are using a particular compiler, and portability is not an issue, note that some compilers do support including a file which may or may not exist, as an extension. For example, see clang's __has_include feature.
Use a tool like GNU Autoconf, that's what it's designed for. (On windows, you may prefer to use CMake).
So in your configure.ac, you'd have a line like:
AC_CHECK_HEADERS([foo.h])
Which, after running configure, would define HAVE_FOO_H, which you can test like this:
#ifdef HAVE_FOO_H
#include "foo.h"
#else
#define BAR 1
#endif
If you intend to go down the autotools route (that is autoconf and automake, because they work well together), I suggest you start with this excellent tutorial.

Resources