lilypond-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: lily/freetype-error.cc: const struct #include ;


From: Alexander Kobel
Subject: Re: lily/freetype-error.cc: const struct #include ;
Date: Tue, 07 Sep 2010 01:28:57 +0200
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100713 Lightning/1.0b1 Thunderbird/3.0.6

 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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]