Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Avoid duplication of code using C token pasters

This is what my #define macro looks like:

#define CUSTOM_COMPARATOR(table, column, a, b)                          \
    do {                                                                \
        const struct db_##table *row1 = a;                              \
        const struct db_##table *row2 = b;                              \
                                                                        \
        /* Insert lot of code here with multiple row->##column usage */ \
        return strcmp(row1->##column->name1, row2->##column->name2);    \
    } while (0)

I have to generate multiple definitions based on different table and column types. These definitions are preprocessed and called in multiple functions:

static int
db_table_sometable_somecolumn_comparator(const void *a, const void *b) {
    CUSTOM_COMPARATOR(sometable, somecolumn, a, b);
}

static int
db_table_someothertable_someothercolumn_comparator(const void *a, const void *b) {
    CUSTOM_COMPARATOR(someothertable, someothercolumn, a, b);
}

Basically I want to avoid the duplication of code inside CUSTOM_COMPARATOR. When I compile this gcc complains that pasting "->" and "somecolumn" does not give a valid preprocessing token which is understandable since -> breaks the token. It works on db_##table because it produces a single token.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Nonetheless, is there any way I can achieve this? I have like 10s of table/columns with just name change but share the same logic mentioned in CUSTOM_COMPARATOR which is also 50 LoC in real.

>Solution :

Don’t try to paste the column name to make a new token. Remember that whitespace in C is ignored, so you can simply do this:

        return strcmp(row1-> column ->name1, row2-> column ->name2);

This is accepted by the preprocessor, and expands to, e.g. with gcc -E:

static int
db_table_sometable_somecolumn_comparator(const void *a, const void *b) {
    do { const struct db_sometable *row1 = a; const struct db_sometable *row2 = b; return strcmp(row1-> somecolumn ->name1, row2-> somecolumn ->name2); };
}

static int
db_table_someothertable_someothercolumn_comparator(const void *a, const void *b) {
    do { const struct db_someothertable *row1 = a; const struct db_someothertable *row2 = b; return strcmp(row1-> someothercolumn ->name1, row2-> someothercolumn ->name2); };
}

which is perfectly valid C.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading