Unusual usage of .h file in C

Solution 1:

Preprocessor directives like #include are just doing some textual substitution (see the documentation of GNU cpp inside GCC). It can occur at any place (outside of comments and string literals).

However, a #include should have its # as the first non-blank character of its line. So you'll code

float h[N] = {
  #include "f1.h"
};

The original question did not have #include on its own line, so had wrong code.

It is not normal practice, but it is permitted practice. In that case, I would suggest using some other extension than .h e.g. use #include "f1.def" or #include "f1.data" ...

Ask your compiler to show you the preprocessed form. With GCC compile with gcc -C -E -Wall yoursource.c > yoursource.i and look with an editor or a pager into the generated yoursource.i

I actually prefer to have such data in its own source file. So I would instead suggest to generate a self-contained h-data.c file using e.g. some tool like GNU awk (so file h-data.c would start with const float h[345] = { and end with };...) And if it is a constant data, better declare it const float h[] (so it could sit in read-only segment like .rodata on Linux). Also, if the embedded data is big, the compiler might take time to (uselessly) optimize it (then you could compile your h-data.c quickly without optimizations).

Solution 2:

As already explained in previous answers, it is not normal practice but it's a valid one.

Here is an alternative solution:

File f1.h:

#ifndef F1_H
#define F1_H

#define F1_ARRAY                   \
{                                  \
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \
    10,11,12,13,14,15,16,17,18,19, \
    20,21,22,23,24,25,26,27,28,29, \
    30,31,32,33,34,35,36,37,38,39, \
    40,41,42,43,44,45,46,47,48,49, \
    50,51,52,53,54,55,56,57,58,59, \
    60,61,62,63,64,65,66,67,68,69, \
    70,71,72,73,74,75,76,77,78,79, \
    80,81,82,83,84,85,86,87,88,89, \
    90,91,92,93,94,95,96,97,98,99  \
}

// Values above used as an example

#endif

File f1.c:

#include "f1.h"

float h[] = F1_ARRAY;

#define N (sizeof(h)/sizeof(*h))

...

Solution 3:

So, is it normal practice to use float h[N] = { #include “f1.h” }; this way?

It is not normal, but it is valid (will be accepted by the compiler).

Advantages of using this: it spares you the small amount of effort that would be required to think of a better solution.

Disadvantages:

  • it increases WTF/SLOC ratio of your code.
  • it introduces unusual syntax, both in client code and in the included code.
  • in order to understand what f1.h does, you would have to look at how it is used (this means either you need to add extra docs to your project to explain this beast, or people will have to read the code to see what it means - neither solution is acceptable)

This is one of those cases where an extra 20 minutes spent thinking before writing the code, can spare you a few tens of hours of cursing code and developers during the lifetime of the project.

Solution 4:

No, it is not normal practice.

There is little to no advantage in using such a format directly, instead the data could be generated in a separate source file, or at least a complete definition could be formed in this case.


There is however a "pattern" which involves including a file in such random places: X-Macros, such as those.

The usage of X-macro is to define a collection once and use it in various places. The single definition ensuring the coherence of the whole. As a trivial example, consider:

// def.inc
MYPROJECT_DEF_MACRO(Error,   Red,    0xff0000)
MYPROJECT_DEF_MACRO(Warning, Orange, 0xffa500)
MYPROJECT_DEF_MACRO(Correct, Green,  0x7fff00)

which can now be used in multiple ways:

// MessageCategory.hpp
#ifndef MYPROJECT_MESSAGE_CATEGORY_HPP_INCLUDED
#define MYPROJECT_MESSAGE_CATEGORY_HPP_INCLUDED

namespace myproject {

    enum class MessageCategory {
#   define MYPROJECT_DEF_MACRO(Name_, dummy0_, dummy1_) Name_,
#   include "def.inc"
#   undef MYPROJECT_DEF_MACRO
    NumberOfMessageCategories
    }; // enum class MessageCategory

    enum class MessageColor {
#   define MYPROJECT_DEF_MACRO(dumm0_, Color_, dummy1_) Color_,
#   include "def.inc"
#   undef MYPROJECT_DEF_MACRO
    NumberOfMessageColors
    }; // enum class MessageColor

    MessageColor getAssociatedColorName(MessageCategory category);

    RGBColor getAssociatedColorCode(MessageCategory category);

} // namespace myproject

#endif // MYPROJECT_MESSAGE_CATEGORY_HPP_INCLUDED

Solution 5:

A long time ago people overused the preprocessor. See for instance the XPM file format which was designed so that people could:

#include "myimage.xpm"

in their C code.

It's not considered good any more.

The OP's code looks like C so I will talk about C

Why is it overuse of the preprocessor ?

The preprocessor #include directive is intended to include source code. In this case and in the OP's case it is not real source code but data.

Why is it considered bad ?

Because it is very inflexible. You cannot change the image without recompiling the whole application. You cannot even include two images with the same name because it will produce non-compilable code. In the OP's case, he cannot change the data without recompiling the application.

Another issue is that it creates a tight-coupling between the data and the source code, for instance the data file must contain at least the number of values specified by the N macro defined in the source code file.

The tight-coupling also imposes a format to your data, for instance if you want to store a 10x10 matrix values, you can either choose to use a single dimension array or a two dimensional array in your source code. Switching from one format to the other will impose a change in your data file.

This problem of loading data is easily solved by using the standard I/O functions. If you really need to include some default images you can give a default path to the images in your source code. This will at least allow the user to change this value (through a #define or -D option at compile time), or to update the image file without need to recompile.

In the OP's case, its code would be more reusable if the FIR coeficients and x, y vectors where passed as arguments. You could create a structto hold togeteher these values. The code would not be inefficient, and it would become reusable even with other coeficients. The coeficients could be loaded at startup from a default file unless the user pass a command line parameter overriding the file path. This would remove the need for any global variables and makes the intentions of the programmer explicit. You could even use the same FIR function in two threads, provided each thread has got its own struct.

When is it acceptable ?

When you cannot do dynamic loading of data. In this case you have to load your data statically and you are forced to use such techniques.

We should note that not having access to files means you're programming for a very limited platform, and as such you have to do tradeoffs. This will be the case if your code run on a micro-controller for instance.

But even in that case I would prefer to create a real C source file instead of including floating point values from a semi-formatted file.

For instance, providing a real C function returning the coefficients, rather than having a semi-formatted data file. This C function could then be defined in two different files, one using I/O for development purposes, and enother one returning static data for the release build. You would compile the correct source file conditionnaly.