Compile time configuration using if-statements - c

In the embedded C world, we frequently store configuration details in headers so that a library can be built for a specific task, minimizing overhead and compiled size.
One example would be:
//libnameConf.h
#define LIBNAME_WAVE LIBNAME_A
typedef enum {
LIBNAME_A,
LIBNAME_B,
LIBNAME_C
} libname_wave_t;
//libname.c
double coef_arr_a[100] = {...};
double coef_arr_b[100] = {...};
double coef_arr_c[100] = {...};
if (LIBNAME_WAVE == LIBNAME_A) {
somestruct.waveCoefs = coef_arr_a;
//do other coef_arr_a specific stuff
} else if (LIBNAME_WAVE == LIBNAME_B) {...}
For this particular case we're using an if-statement that the compiler will obviously collapse which is a good thing because we only want a reference to coef_arr_a so that the others won't be compiled into the binary and take up space.
Unfortunately, this yields the warning
warning: comparison between 'enum <anonymous>' and 'enum <anonymous>' [-Wenum-compare]
Is there a better way that avoids this warning?

How about using macros only instead of using variables and enumerations.
//libnameConf.h
#define LIBNAME_A
// #define LIBNAME_B // Uncomment this line and both comment the above line while changing libs.
Then we use several conditional compilation statements like this.
//libname.c
double coef_arr_a[100] = {...};
double coef_arr_b[100] = {...};
#ifdef LIBNAME_A
somestruct.waveCoefs = coef_arr_a;
//do other coef_arr_a specific stuff
#endif
#ifdef LIBNAME_B
somestruct.waveCoefs = coef_arr_b;
#endif

Sounds like you need conditional compilaiton in C but the way you're doing it is not correct. Conditional compilation is a concept of the preprocessor which is run before the compiler. The point of preprocessor is to manipulate the source code before it is fed to the compiler. Since you haven't used any preprocessor conditionals, all the source code is fed to the compiler regardless of your compile-time conditionals. You should definitely use preprocessor conditionals to reduce your binary.

Related

Is it possible to write a _Static_assert in GCC/GNU C that would verify the layout of bit fields in memory at compile time?

Suppose that I have the following definitions:
#include <stdbool.h>
#include <stdint.h>
#define ASSERT(cond) _Static_assert(cond, #cond)
typedef union {
struct {
bool bit0:1;
bool bit1:1;
bool bit2:1;
bool bit3:1;
bool bit4:1;
bool bit5:1;
bool bit6:1;
bool bit7:1;
};
uint8_t bits;
} byte;
ASSERT(sizeof(byte) == sizeof(uint8_t));
Is it possible to write a code, such as
#include <assert.h>
// ...
assert(((byte) { .bit0 = 1 }).bits == 0b00000001);
assert(((byte) { .bit1 = 1 }).bits == 0b00000010);
assert(((byte) { .bit2 = 1 }).bits == 0b00000100);
assert(((byte) { .bit3 = 1 }).bits == 0b00001000);
assert(((byte) { .bit4 = 1 }).bits == 0b00010000);
assert(((byte) { .bit5 = 1 }).bits == 0b00100000);
assert(((byte) { .bit6 = 1 }).bits == 0b01000000);
assert(((byte) { .bit7 = 1 }).bits == 0b10000000);
// ...
that would cause a compile-time failure if the above conditions weren't satisfied?
(When I try to place the conditions in the ASSERT macro, the compiler complains that expression in static assertion is not constant, which of course makes perfect sense)
The solution is allowed to use the GNU extensions to the C language.
I don't think you can.
_Static_assert is required to verify that the argument expression satisfies standard C's requirements for an integer constant expression.
There are ways, which on gcc can sometimes turn a boolean expression that doesn't satisfy those requirements but are compile-time-known to the optimizer into a compile-time error or warning.
E.g., :
#include <assert.h>
#if __GNUC__ && !__clang__
#define $SassertIfUCan0(X) \
(__extension__({ /*ellicit a -Wvla-larger-than */ \
(!__builtin_constant_p(X)) ? 0 : \
({ char volatile $SassertIfUCan0_[ (!__builtin_constant_p(X)||(X)) ? 1:-1]; \
$SassertIfUCan0_[0]=0,0;}); \
__auto_type $SassertIfUCan0 = X; \
assert($SassertIfUCan0); \
0; \
}))
#endif
int main(int C, char **V)
{
int x = 0; $SassertIfUCan0(x);
//these also ellicit compile-time errrors:
/*$SassertIfUCan0(C-C);*/
/*$SassertIfUCan0(C*0);*/
}
can turn the nullness of the compile-time known variable x, which isn't technically an integer constant, into a compile/time warning/error
("-Wvla-larger-than").
Unfortunately, the macro doesn't work with every expression and that includes your bitfield-based example.
(I wish compilers had a mechanism for failing compilation if an expression happens to be compile-time known and false.)
So AFAIK, the closest thing you can do is compile-time detect platforms whose ABI is known to guarantee your required bitfield layout:
#if __linux__ && __x86_64__
#elif 0//...
//...
#else
#error "bitfields not known to be little-endian"
#endif
I think, this is an X-Y problem: You are asking about checking the layout of bitfields when you really want to write code that is portable across different implementations of bitfields. So:
If you don't try to communicate your bitfield to another machine, or store it in a file where a different machine may read it, just forget about the implementation detail of how the bits are ordered. Just access them via the bitfield names, and be done with it.
If you need to communicate the structures containing these bitfields, declare a uint8_t and the appropriate set of bit flag constants (#define BIT7 (1u << 7), etc.). Bytes never change value when they are transferred from one machine to another, so myFlags & BIT7 is guaranteed to yield the same result everywhere.
Note that it is important to either use a single byte to store the flags, or handle the problem of endianess explicitly.
On GNU Linux, you might find <features.h> and /usr/x86_64-linux-gnu/include/linux/byteorder/big_endian.h
The solution is allowed to use the GNU extensions to the C language.
With most recent GCC compilers, you could provide your own GCC plugin defining your __your_builtin_endian__ compiler builtin. Notice that some GCC compilers are built without plugin support (e.g. RedHat did that). Check by running gcc -v alone.
Once your plugin defines __your_builtin_endian__, you could use that in static_assert. Or have your plugin define and implement some #pragma MYPLUGIN check endian which would make a compile-time error in some cases.
Do budget a few weeks of fulltime work for such a plugin. It is GCC version specific (not always the same C++ code for a GCC 9 and GCC 10 plugin).
Consider also using autoconf (at least if you do not need any cross-compilation).
Not strickly within the limits of the question, but may provide for more portable solution.
The static assertion has limits to the expressions, and it will NOT be able to evaluate expression from a union.
As an alternative, and assuming the code will be built by a makefile (or equivalent), consider adding a a step to the build to force the condition
static.verify: static_check.c
cc -o static_check static_check.c
./static_check
touch $#
# Make the static.verify dependency for building objects/executable.
a.o: static.verify
Basically, making it a requirement to run the small program 'static_check.c'. The program can produce any required error message. Should exit with non-zero return status to indicate an error.

Restoring definitions and macros

Is there a way to restore macros in C, so that you can define a new macro, under which name probably other macros are already defined, and redefine it with the previous value?
so that when new defined macros are deleted and eventually redefined macros are resetted to its previous state?
Example:
// a macro parameter used in a library
#define size 10
#include <library/use_size.h>
//here the command/pragma to save the definitions
#define size (100 / sizeof(size_t))
// some use of size ...
//here the command/pragma to reset the definitions
#include <library/allocator_with_size.h>
#undef size
// use size as a variable name
size_t size = 0;
//...
size += 123;
Edit: I do not want to use #undef, because it does not restore old macros. Also, if you have many macros, eg for using them in a X-macro-list (in a long repetitive code/declaration of constant arrays and structs), it looks ugly, if there are many #undef directives.
Ok I researched myself and found the pragmas push_macro and pop_macro, supported by clang, gcc and visual c++. I use clang, so it is no problem to use it. The disadvantage: it does not reduce the line-count if you want to restore multiple macros ¹, but it restores the macros and can be encapsulated:
#pragma push_macro("size")
#define size (100 / sizeof(size_t))
#pragma pop_macro("size")
Notes:
¹ I defined multiple macros and tried to restore them with:
#pragma push_macro("size", "key", "name")
// define them all
#pragma pop_macro("size", "key", "name")
But that is not implemented into the compilers yet. So for each macro there must be a seperate line to do this.

How can a declared C function have no implementation?

I am baffled by the lack of implementation code for the function glade_project_get_type in the following code snippets.
From the .c file:
project = g_object_new (GLADE_TYPE_PROJECT, NULL);
From the associated header file:
#define GLADE_TYPE_PROJECT (glade_project_get_type ())
This appears to be the declaration of glade_project_get_type():
GType glade_project_get_type (void) G_GNUC_CONST;
/* From glib/gmacros.h:
#define G_GNUC_CONST __attribute__((__const__))
__attribute__((const)) function attribute
Many functions examine only the arguments passed to them and have no effects
except for the return value.
If a function is known to operate only on its arguments then it can be subject
to common sub-expression elimination and loop optimizations.
*/
Nowhere can I find the implementation code for glade_project_get_type() but the software compiles without error, so obviously there is something that I don't understand.
I expected there to be something somewhere like:
GType glade_project_get_type (void)
{
GType aType;
< some code giving a value to aType >
return aType
}
So, what don't I understand about C programming?
The code implementing glade_project_get_type is in the library libgladeui, which is compiled separately and linked with the glade executable.
The source code for libgladeui is shipped along with that of glade. The definition of the function glade_project_get_type is in the file glade-project.c. You won't find the string glade_project_get_type in that file because the actual code for the function is the result of a complicated macro expansion, coming from the following lines of glade_project_get_type:
G_DEFINE_TYPE_WITH_CODE (GladeProject, glade_project, G_TYPE_OBJECT,
G_ADD_PRIVATE (GladeProject)
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
glade_project_model_iface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
glade_project_drag_source_init))
This macro is defined in the header files for glib, specifically gobject/gtype.h. At some point in its expansion, I would guess that token pasting (the ## preprocessor directive) will be used to take one of the tokens passed to the macro (here glade_project) and define a function whose name is that token concatenated with _get_type.
Here is a simple example of what is going on here:
#define MAKE_FUNC(name, val) int my_ ## name ## _function (void) { return val; }
MAKE_FUNC(magic, 42)
int main(void) {
printf("%d\n", my_magic_function());
return 0;
}
Although at first glance, the program doesn't appear to include a definition of my_magic_function, the macro MAKE_FUNC actually expands to create it. The expansion of MAKE_FUNC(magic, 42) is simply
int my_magic_function(void) { return 42; }
The function glade_project_get_type() is compiled into a library, e.g. libglade. The raw source code of this library doesn't contain a definition exactly, because the source code for this function is generated from a template, which can be viewed here.
The headers you are using only describe the functions available. Headers rarely contain actual source code in C, they generally just contain function and type definitions. The compiler uses the information in the header to know what return types and argument types the functions has or what members are in a struct or union. It is the linker's job to actually make sure the functions you are using have definitions. The linker will link your source code with the precompiled libglade library and connect everything up.

Using if clause instead of processor #ifdef

I am using a #ifdef block to conditionally include a block of code based on -Dflag passed to the compiler.
Is there a way to implement this with an if?
Something along the lines of:
if (defined(flag)) {
}
You use preprocessor to produce a different flag, which could be tested with a run-time if statement, like this:
#ifdef flag
#define flag_defined 1
#else
#define flag_defined 0
#endif
Now you can do this:
if (flag_defined) ...
If you define a macro so that it evaluates to either zero or nonzero, then you can use it in the condition of the if statement. Since it's a compile-time constant, in case it's zero, the dead code eliminator pass in the compiler will remove the unreachable code anyway.
If you are willing to give flag a value (0 or 1) instead of defining it or not, you can do
cc -Dflag=1 file.c
with
if (flag) { ... }
without messing up your code with ugly #ifdefs. You are also protected against forgetting to define flag at all: in this case your compiler treats flag as an identifier. Since you never declared it, you'll get a compile time error about an undeclared or undefined symbol flag.
No, you can't use a C if statement to check if a preprocessor token is defined.
You can use one of these forms though
#ifdef flag
...
#endif
#if defined(flag)
...
#endif
You can however check if the token evaluates to a true/false C expression,
if you use -Dflag=1 you can do
if (flag) {
...
}
And if you want to turn it off, you can define the macro as -Dflag=0
Following this you can define a new preprocessor token that you can check with a C if statement. e.g.
#ifdef flag
#define FLAG_SET 1
#else
#define FLAG_SET 0
#endif
if(FLAG_SET) { //the flag macro was defined
...
}
If all you want to do is is check whether the flag is defined, there's no point to all of this, just use #ifdef. With a C if statement, the most C compilers will optimize away the code, there's nothing you could change at runtime to get any benefit of not using the preprocessor.
#ifdef FLAG
#define FLAG_VALUE 1
#else
#define FLAG_VALUE 0
#endif
int flag = FLAG_VALUE;
...
if(flag)
{
....
}
Alternatively just use -DFLAG_VALUE=1 or -DFLAG_VALUE=0 as appropriate and use FLAG_VALUE directly.
If you plan on being able to change the FLAG_VALUE at runtime you will need a variable. If you change in non-obvious ways (e.g. via a debugger or through other loader trickery) make sure to declare it volatile, otherwise the compiler might be able to do dead-code elimination and remove huge chunks of code.
Also, if you don't plan on changing the value of flag after initializing, then you should probably make it const.

#define an object with no value

I am now read some c code. And is not very clear about the "#define someting" expression.
For example, I saw this code:
typedef enum cairo_path_op {
CAIRO_PATH_OP_MOVE_TO = 0,
CAIRO_PATH_OP_LINE_TO = 1,
CAIRO_PATH_OP_CURVE_TO = 2,
CAIRO_PATH_OP_CLOSE_PATH = 3
} __attribute__ ((packed)) cairo_path_op_t; /* Don't want 32 bits if we can avoid it. */
#ifndef __GNUC__
#define __attribute__(x)
#endif
I take attention to the "__attribute__(x)". since in other header file , the "__attribute__(x)" is defined with no value, but how it take effect in the enum "cairo_path_op" define?
This is for portability reasons.
__attribute__() is a GCC extension for modifying various properties and behavior of functions, variables, types, etc.
If a non-GCC-compatible compiler tries to compile code that uses this extension, it won't able to do so and will throw a syntax error.
In order to avoid this, the author of the code makes the preprocessor replace this keyword with nothing if __GNUC__ is not defined (i. e. if the compiler is not a GCC-compatible one), so that the code builds on a bigger variety of platforms.

Resources