1

I'm in the process of porting some code from the GIMP source code base into a program I am writing. Part of the code (/gimp-2.8.10//modules/display-filter-color-blind.c) references a macro called GIMP_CAIRO_ARGB32_SET_PIXEL (gimp-2.8.10//libgimpcolor/gimpcairocolor.h). Within that macro there is something called G_STMT_START/G_STMT_END. My compiler (Mac OSX via Xcode with the default compiler) is complaining with the error "Use of undeclared identifier 'G_STMT_START'" I know it is not a scoping issue with where I put the macros (in a header file called globals.h that I include in my .h) because the compiler is not complaining about the GIMP_CAIRO_ARGB32_SET_PIXEL define.

Does anyone know whats going on here? I've attempted to grep through all instances of G_STMT_START in the GIMP source but have not found anything that seems to define G_STMT_START/G_STMT_END. I also found sort of an explanation in the GIMP toolkit documentation, but it's far from helpful (for me at least).

This is the full macro that I am trying to use:

/**
 * GIMP_CAIRO_ARGB32_SET_PIXEL:
 * @d: pointer to the destination buffer
 * @r: red component, not pre-multiplied
 * @g: green component, not pre-multiplied
 * @b: blue component, not pre-multiplied
 * @a: alpha component
 *
 * Sets a single pixel in an Cairo image surface in %CAIRO_FORMAT_ARGB32.
 *
 * Since: GIMP 2.6
 **/
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define GIMP_CAIRO_ARGB32_SET_PIXEL(d, r, g, b, a) \
  G_STMT_START {                                   \
    const guint tr = (a) * (r) + 0x80;             \
    const guint tg = (a) * (g) + 0x80;             \
    const guint tb = (a) * (b) + 0x80;             \
    (d)[0] = (((tb) >> 8) + (tb)) >> 8;            \
    (d)[1] = (((tg) >> 8) + (tg)) >> 8;            \
    (d)[2] = (((tr) >> 8) + (tr)) >> 8;            \
    (d)[3] = (a);                                  \
  } G_STMT_END
#else
#define GIMP_CAIRO_ARGB32_SET_PIXEL(d, r, g, b, a) \
  G_STMT_START {                                   \
    const guint tr = (a) * (r) + 0x80;             \
    const guint tg = (a) * (g) + 0x80;             \
    const guint tb = (a) * (b) + 0x80;             \
    (d)[0] = (a);                                  \
    (d)[1] = (((tr) >> 8) + (tr)) >> 8;            \
    (d)[2] = (((tg) >> 8) + (tg)) >> 8;            \
    (d)[3] = (((tb) >> 8) + (tb)) >> 8;            \
  } G_STMT_END
#endif

Thanks for any help with this!

Matthew Herbst
  • 29,477
  • 23
  • 85
  • 128

3 Answers3

3

I had no idea what this might be either (although now that I know, I'm telling myself that I could probably have guessed), but all it took to find out was entering G_STMT_START into Google and clicking on the first result.

That page, documentation from the Glib manual, reveals that it is a macro designed to be used within multi-statement macros.

G_STMT_START

#define     G_STMT_START

Used within multi-statement macros so that they can be used in places where only one statement is expected by the compiler.

G_STMT_END

#define     G_STMT_END

Used within multi-statement macros so that they can be used in places where only one statement is expected by the compiler.

Later on in the search results, you'll get one or more copies of the gmacros.h header file, where these macros are actually defined:

/* Provide simple macro statement wrappers (adapted from Perl):
 *  G_STMT_START { statements; } G_STMT_END;
 *  can be used as a single statement, as in
 *  if (x) G_STMT_START { ... } G_STMT_END; else ...
 *
 *  For gcc we will wrap the statements within `({' and `})' braces.
 *  For SunOS they will be wrapped within `if (1)' and `else (void) 0',
 *  and otherwise within `do' and `while (0)'.
 */
#if !(defined (G_STMT_START) && defined (G_STMT_END))
#  if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus)
#    define G_STMT_START    (void) __extension__ (
#    define G_STMT_END      )
#  else
#    if (defined (sun) || defined (__sun__))
#      define G_STMT_START  if (1)
#      define G_STMT_END    else (void)0
#    else
#      define G_STMT_START  do
#      define G_STMT_END    while (0)
#    endif
#  endif
#endif

From that, it becomes pretty clear that these macros are just implementing the standard idiom, except on GCC where they use the extension intended for precisely this purpose.

I'd figure that there will be other parts of the GIMP code that will depend on the Glib headers, so you'll probably want to include them if you're using its code. But if not, there's enough information here to implement the relevant portions of code yourself.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Fascinating. I didn't know about the standard idiom aspect - I'm very new to macros. And thanks for the explanation - I had found the Glib manual but it still didn't mean much to me out of context. – Matthew Herbst Apr 22 '14 at 03:56
  • 1
    @Matthew Ah, well then in that case, stay pure! Especially in C++, there are *far* better ways of writing code than to abuse macros. Even C has `inline` functions now. – Cody Gray - on strike Apr 22 '14 at 04:19
  • Are macros inlined by the compiler? Otherwise it seems like a lot of branching since I have to make three macro calls for every pixel I go through – Matthew Herbst Apr 22 '14 at 05:35
  • Macros are actually inlined by the *preprocessor*, which is a step that occurs before compilation. You can think of them as basically being search-and-replaced everywhere in your code. If that sounds slightly dangerous, well then now you understand why people say to avoid macros whenever possible! There are some neat tricks you can do, but more often than not, those tricks can get you into trouble. The effect of an inline function is nearly equivalent, except that inline functions are handled by the compiler and linker, which can actually understand and parse C++ code. – Cody Gray - on strike Apr 22 '14 at 05:39
  • 1
    I don't mean this to be condescending, but C++ (and C from which it hails) is a difficult language to pick up with a day or two of study. If you're going to be writing code in C++, I *highly* recommend picking up and studying [a good book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) on it. Otherwise, you're going to make mistakes that you'll regret later on. – Cody Gray - on strike Apr 22 '14 at 05:41
  • I appreciate the link! My background is web scripting and Java, so I probably should read up on the intricacies of C++/C. Right now i'm working on my first iOS app, so it's been an interesting mix of things I've had to learn. – Matthew Herbst Apr 22 '14 at 14:08
1

G_STMT_START and G_STMT_END are macros in the Gnome Glib library that gimp depends on.

They are defined in gmacros.h.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
0

Currently, the documentation of GTK 4 - GLib 2.0 no longer includes miscellaneous macros like G_STMT_START, G_STMT_END, etc. If you look through old documentation from other sources like geany or the web archive, you can see that they are defined as

#define G_STMT_START  do
#define G_STMT_END    while (0)

Actually, in <glib/gmacros.h> (for GLib 2.0), the real definitions are:

#if !(defined (G_STMT_START) && defined (G_STMT_END))
#define G_STMT_START  do
#if defined (_MSC_VER) && (_MSC_VER >= 1500)
#define G_STMT_END \
    __pragma(warning(push)) \
    __pragma(warning(disable:4127)) \
    while(0) \
    __pragma(warning(pop))
#else
#define G_STMT_END    while (0)
#endif
#endif

It just wraps a do ... while(0) block. The effect of this macro pair is well introduced by Cody Gray's answer - the standard idiom.

Ayka
  • 11
  • 1
  • 2