http://www.perlmonks.org?node_id=1203134


in reply to [OT] Abusing the C preprocessor

afoken:

Update: I think I misunderstood what was wanted originally (removal of warnings and minimization of unused code), so while my original answer did what I wanted it to do, I doubt it did what afoken wanted done. So here's what I think you want.

First, you can create a library of the various methods you may want to include:

$ cat lib_int.c int compare_int(const void *a, const void *b) { return *(int *)a - *(int *)b; } $ cat lib_double.c int compare_double(const void *a, const void* b) { return *(double *)a - *(double *)b; } $ gcc -c -o lib_int.o lib_int.c $ gcc -c -o lib_double.o lib_double.c $ ar cr libtypes.a lib_int.o lib_double.o

Now your program can simply use the extern directive to tell the linker which items to pull into your executable:

$ cat foo.c #include <stdio.h> #include <stdlib.h> #if defined(DO_INT) int a1[] = { 1, 100, 5, 50, 25 }; #endif #if defined(DO_DOUBLE) double a2[] = { 1.0, 10.0, 5.0, 25.0 }; #endif int (*cmp_fn)(const void *, const void *); #define CFG_ADD(TYPE) \ extern int compare_ ## TYPE(const void*, const void*); \ cmp_fn = compare_ ## TYPE int main(int argc, char **argv) { #if defined(DO_INT) CFG_ADD(int); qsort(a1, sizeof(a1)/sizeof(a1[0]), sizeof(a1[0]), cmp_fn); for (int i=0; i<sizeof(a1)/sizeof(a1[0]); i++) { printf("%d, ", a1[i]); } #endif #if defined(DO_DOUBLE) printf("\n\n"); CFG_ADD(double); qsort(a2, sizeof(a2)/sizeof(a2[0]), sizeof(a2[0]), cmp_fn); for (int i=0; i<sizeof(a2)/sizeof(a2[0]); i++) { printf("%f, ", a2[i]); } #endif } $ gcc foo.c -DDO_INT -L. -ltypes -o foo_int $ gcc foo.c -DDO_DOUBLE -L. -ltypes -o foo_double $ gcc foo.c -DDO_INT -DDO_DOUBLE -L. -ltypes -o foo_both

And you can tell that the linker did what it wanted:

$ ./foo_int 1, 5, 25, 50, 100, $ ./foo_double 1.000000, 5.000000, 10.000000, 25.000000, $ ./foo_both 1, 5, 25, 50, 100, 1.000000, 5.000000, 10.000000, 25.000000, $ nm foo_int.exe | grep compare 0000000100403040 r .rdata$.refptr.compare_int 0000000100403040 R .refptr.compare_int 0000000100401170 T compare_int $ nm foo_double.exe | grep compare 0000000100403040 r .rdata$.refptr.compare_double 0000000100403040 R .refptr.compare_double 00000001004011a0 T compare_double $ nm foo_both.exe | grep compare 0000000100403040 r .rdata$.refptr.compare_double 0000000100403050 r .rdata$.refptr.compare_int 0000000100403040 R .refptr.compare_double 0000000100403050 R .refptr.compare_int 0000000100401230 T compare_double 0000000100401210 T compare_int

I hope this gets you where you want to go...

My original response was:

If you don't mind it, you could use a function pointer to hold the sorting function, and let your macro set the value, like:

$ cat foo.c #include <stdio.h> #include <stdlib.h> int compare_int(const void *a, const void *b) { return *(int *)a - *(int *)b; } int compare_double(const void *a, const void* b) { return *(double *)a - *(double *)b; } int a1[] = { 1, 100, 5, 50, 25 }; double a2[] = { 1.0, 10.0, 5.0, 25.0 }; int (*cmp_fn)(const void *, const void *); #define CFG_ADD(TYPE) cmp_fn = compare_ ## TYPE; int main(int argc, char **argv) { CFG_ADD(int); qsort(a1, sizeof(a1)/sizeof(a1[0]), sizeof(a1[0]), cmp_fn); for (int i=0; i<sizeof(a1)/sizeof(a1[0]); i++) { printf("%d, ", a1[i]); } printf("\n\n"); CFG_ADD(double); qsort(a2, sizeof(a2)/sizeof(a2[0]), sizeof(a2[0]), cmp_fn); for (int i=0; i<sizeof(a2)/sizeof(a2[0]); i++) { printf("%f, ", a2[i]); } } $ gcc foo.c -o foo $ ./foo 1, 5, 25, 50, 100, 1.000000, 5.000000, 10.000000, 25.000000,

If that's not good for you, let me know and I'll try to think up something else.

...roboticus

When your only tool is a hammer, all problems look like your thumb.

Replies are listed 'Best First'.
Re^2: [OT] Abusing the C preprocessor
by afoken (Chancellor) on Nov 11, 2017 at 20:28 UTC

    Yes, a library would be the cleanest way to go. Except that it would require a good amount of changes. Currently, all we need to do to include the filtering software in a project is to copy a source file and a header file into the project, and write a simple configuration file. That works for all of our platforms and build environments. (Actually, this is what can be done in about a week. So far, we need to change the source file for each project.)

    I'll rely on gcc optimizing away unused functions, and disable the warnings for the compare functions that may be unused. (Re^2: [OT] Abusing the C preprocessor).

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)