Note that there are some explanatory texts on larger screens.

plurals
  1. POPortable nested functions in C
    text
    copied!<p>Is it possible to write portable C code using nested functions/blocks?</p> <p>I understand that gcc only supports nested functions as an non-standard extension, and clang only supports blocks - but is there a way to write code that will compile on both using standard C with MACROS?</p> <p>If it is not possible - what is the best work around? As an example, how would one implement a portable version of the following sort that takes a parameter? Trivial example in GCC:</p> <pre><code>int main(int argc, char*[] argv) { char reverse = 0; int cmp_func(const void *a, const void *b) { const int* aa = (const int)a; const int* bb = (const int)b; return (reverse) ? aa - bb : bb - aa; } int list[8] = {1,2,3,4,5,20,100,200}; qsort(list, 8, sizeof(int), &amp;cmp_func); } </code></pre> <p>A similar example could be put together using Blocks in Clang. Ideally the solution should be thread-safe (so avoid global variables).</p> <p><strong>Edit:</strong> For clarity, lets assume "standard" means C99. The above is a trivial example. What I'm after is a C99 approach to a sort that requires some parameters. Here it just uses a char as a boolean, but I'm after a solution that would take multiple integers etc. It looks like this might not be possible without global variables. </p> <p><strong>Edit 2:</strong> I realised that passing a void pointer along with a function pointer enables you to do everything that can be done with nested functions. Thanks to @Quuxplusone for suggesting <code>qsort_r</code> and <code>qsort_s</code>. I've tried to put together a portable wrapper on <code>qsort_r</code> and <code>qsort_s</code>. It takes a comparator function and a void pointer to store state in, thus removing the dependency on nested functions for intricate sorting algorithms -- so you can compile with both GCC and Clang. </p> <pre><code>typedef struct { void *arg; int (*compar)(const void *a1, const void *a2, void *aarg); } SortStruct; int cmp_switch(void *s, const void *aa, const void *bb) { SortStruct *ss = (SortStruct*)s; return (ss-&gt;compar)(aa, bb, ss-&gt;arg); } void sort_r(void *base, size_t nel, size_t width, int (*compar)(const void *a1, const void *a2, void *aarg), void *arg) { #if (defined _GNU_SOURCE || defined __GNU__ || defined __linux__) qsort_r(base, nel, width, compar, arg); #elif (defined __APPLE__ || defined __MACH__ || defined __DARWIN__ || \ defined __FREEBSD__ || defined __BSD__ || \ defined OpenBSD3_1 || defined OpenBSD3_9) SortStruct tmp = {arg, compar}; qsort_r(base, nel, width, &amp;tmp, &amp;cmp_switch); #elif (defined _WIN32 || defined _WIN64 || defined __WINDOWS__) SortStruct tmp = {arg, compar}; qsort_s(*base, nel, width, &amp;cmp_switch, &amp;tmp); #else #error Cannot detect operating system #endif } </code></pre> <p>Note: I haven't tested this on many platforms, so please let me know if you see a bug / this doesn't work on your machine. </p> <p>As an example of usage, I've implemented the same sort as in the chosen answer:</p> <pre><code>int sort_r_cmp(const void *aa, const void *bb, void *arg) { const int *a = aa, *b = bb, *p = arg; int cmp = *a - *b; int inv_start = p[0], inv_end = p[1]; char norm = (*a &lt; inv_start || *a &gt; inv_end || *b &lt; inv_start || *b &gt; inv_end); return norm ? cmp : -cmp; } int arr[18] = {1, 5, 28, 4, 3, 2, 10, 20, 18, 25, 21, 29, 34, 35, 14, 100, 27, 19}; int p[] = {20, 30}; sort_r(arr, 18, sizeof(int), sort_r_cmp, p); </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload