Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is macro abusing ok in libc [closed]

Tags:

c

libc

If I'll tell you I want to implement the following code:

static const uint8_t jump_table[] =
{
    /* ' ' */  1,            0,            0, /* '#' */  4,
               0, /* '%' */ 14,            0, /* '\''*/  6,
      ...
      ...
    /* 't' */ 27, /* 'u' */ 16,            0,            0,
    /* 'x' */ 18,            0, /* 'z' */ 13
};

#define LABEL(Name) do_##Name
#define NOT_IN_JUMP_RANGE(Ch) ((Ch) < ' ' || (Ch) > 'z')
#define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - ' '])
#define REF(Name) &&do_##Name
#define JUMP(ChExpr, table)                   \
do                                            \
{                                             \
    const void *ptr;                          \
    spec = (ChExpr);                          \
    ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \
       : table[CHAR_CLASS (spec)];            \
    goto *ptr;                                \
} while (0)

#define TABLE                                 \
/* Step 0: at the beginning.  */              \
static JUMP_TABLE_TYPE step0_jumps[30] =      \
{                                             \
    REF (form_unknown),                       \
    REF (flag_space),       /* for ' ' */     \
    REF (flag_plus),        /* for '+' */     \
    REF (flag_minus),       /* for '-' */     \
     ...                                      \
    REF (flag_i18n),        /* for 'I' */     \
};

With this usage example:

void usage_example_function(void)
{
    do
    {
      TABLE;

      /* Get current character in format string.  */
      JUMP (*++f, step0_jumps);

      /* ' ' flag.  */
      LABEL (flag_space):
      space = 1;
      JUMP (*++f, step0_jumps);
      ...
      ...
    } while (something)
}

You would tell me that it's unacceptable under any decent coding style standard and committing such code will most likely to do more harm than good.

Now, glibc implements vfprintf with far more macro abusing than this (code above taken from there), yet this code is a part of so many compiled programs and was tested so many times that it makes me fill that any today's (macro) coding standards lack justification.

Why is such a macro abusing is wrong? or alternatively, if such abusing is so wrong, why do we accept such libc implementation?

like image 653
izac89 Avatar asked Jan 22 '26 18:01

izac89


1 Answers

  1. Style rules are guidelines intended to improve communication between software engineers (including current engineers on a team, engineers who will work on the code in the future, and one’s own future self) and to reduce bugs and make software development more efficient. These guidelines should be balanced against other goals, such as performance, necessity, solving problems that arise in particular situations, and so on.

  2. Software in libraries associated with compilers and language implementations is often called upon to serve special purposes. It may be part of the C implementation and may require coordination with the C compiler. As such, it is not entirely subject to the constraints of strictly conforming C code—it may use constructs or features that are particular to the C implementation. (Such use should be clearly documented.) Generally, it is impossible to write a C implementation in strictly conforming C code—a C implementation must interact with hardware and operating system software in ways that are not specified by the C standard. Even where it is possible, it may not be desirable, for reasons of performance and other goals.

  3. One purpose libraries serve is doing all the “dirty” work so you do not have to, or doing the hard or complicated work. Libraries, which are intended to be used by many people, are a good place to invest a lot of engineering effort because work by a few people pays off in benefit to many people. Given the number of direct and indirect users of glibc, the leverage of investment to payoff is huge, so it is worth crafting some strange code if it improves performance or portability. To the extent that such intricate code is needed to obtain a desired result or is desired over alternative methods, putting that code into a library may reduce the amount of such code in the world, by putting it in one place to be used by many people who then do not need to write their own similar code to serve the same purpose.

  4. The code shown in the question is a fairly mild use of preprocessor macros compared to some. Aside from the GCC “labels as values” extension (using && to take the address of a label), it uses standard features and constructs a state machine that should be familiar to anybody with a bachelor’s degree in software engineering. After some study of the code, an experienced software engineer can recognize what it is doing and work with the code fairly easily.

like image 74
Eric Postpischil Avatar answered Jan 25 '26 11:01

Eric Postpischil