On 06/09/10 22:30, Wols Lists wrote:
> Because C doesn't give a monkeys about white space, but the
> pre-processor does. The #include has to be the first thing on the line
> otherwise the pre-processor will screw up, but once the pre-processor
> has done its job, the compiler will happily ignore all the surplus new
> lines.
And, IIRC, the preprocessor even deletes the newline after the include,
which is why the compiler issues a warning if included files do not end
with a newline character. An #include in the next line would be
ignored, or something like this.
const struct Freetype_error_message // this bit is the structure definition
{
FT_Error err_code;
const char* err_msg;
// this bit now declares the array and fills it
} ft_errors[] = ( (1, "message1"), (2, "message2"), (0, 0) ) ;
That bit between the "=" and ";" initialises the array (and I've almost
certainly got my syntax complete crap :-).
The ()s should be {}s, but otherwise it's okay, I think.
Here's my shot to explain it:
Assume you have a list of items like these in a header file, which
should not be copied, but rather only included to stay aware of updates:
/* data.h */
/* Title Artist Year Best Song */
DISC ("Back in Black", "AC/DC", 1980, "Hells Bells")
DISC ("IV", "Led Zeppelin", 1971, "Stairway to Heaven")
DISC ("Thriller", "Michael Jackson", 1982, "Billie Jean")
/* EOF */
Now you want to fill an array of structs, but you only care about the
best songs of each artist. Then you can just do:
/* some .c file */
/* ... */
#define DISC (t, a, y, s) { a, s }
struct BestSongOfArtist {
const char * artist,
const char * song
} artist_song_map[] = {
#include <data.h>
};
#undef DISC
/* ... */
and here you are.
In the case of fterrors.h, stuff is slightly more complicated since
there are default mappings for some macros. Say, most people won't need
the best song, but only the remaining fields, then the file looks like this:
/* default_format_data.h */
#ifndef DATA_START_TOKEN
{
#else
DATA_START_TOKEN
#endif
#ifndef DISC
#define DISC_DEFAULT_USED
#define DISC (t, a, y, s) { t, a, y }
#endif
#include <data.h>
#ifdef DISC_DEFAULT_USED
#undef DISC
#endif
#ifndef DATA_END_TOKEN
}
#else
DATA_END_TOKEN
#endif
/* EOF */
and you could just write
/* some .c file */
/* ... */
struct DiscStruct {
const char * title,
const char * artist,
const char * year
} database[] =
#include <default_format_data.h>
;
/* ... */
It's not a nice coding style, but it keeps all those definitions at only
one place (good thing), and once you figured out what's going on, it's okay.
And as is noted somewhere in the docs for the Boost preprocessor
metaprogramming library, "the preprocessor exists to be used, so don't
shy away". It's bad to clutter the global space with #defines, but it's
equally bad to introduce a lot of non-macro (struct, function,
variable...) names there. (Sadly, namespaces are not an option for C.)
It's not all that rare for larger libraries to have a little stuff
coded like this.
As Wol, I didn't compile this, so my syntax might be crap, too; but the
essence should be there. (And no, I didn't know the release years just
out of my head... ;-))
HTH,
Alexander
_______________________________________________
lilypond-devel mailing list
lilypond-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/lilypond-devel