ネストされた関数/ブロックを使用して移植可能な C コードを作成することは可能ですか?
gcc は非標準拡張機能としてネストされた関数のみをサポートし、clang はブロックのみをサポートすることを理解していますが、MACROS を使用して標準 C を使用して両方でコンパイルするコードを作成する方法はありますか?
それが不可能な場合、最善の回避策は何ですか? 例として、次のようなパラメーターを受け取る移植可能なバージョンをどのように実装しますか? GCC での簡単な例:
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), &cmp_func);
}
同様の例は、Clang の Blocks を使用してまとめることができます。理想的には、ソリューションはスレッドセーフであるべきです (そのため、グローバル変数は避けてください)。
編集:明確にするために、「標準」はC99を意味すると仮定しましょう。上記は些細な例です。私が求めているのは、いくつかのパラメーターを必要とする並べ替えに対する C99 のアプローチです。ここではブール値として char を使用していますが、複数の整数などを取るソリューションを求めています。これは、グローバル変数なしでは不可能なようです。
編集 2:関数ポインターと共に void ポインターを渡すと、ネストされた関数で実行できるすべてのことを実行できることに気付きました。qsort_r
提案してくれた@Quuxplusoneに感謝しqsort_s
ます。と に移植可能なラッパーをまとめようとしましqsort_r
たqsort_s
。コンパレーター関数と状態を格納する void ポインターを使用するため、複雑な並べ替えアルゴリズムのネストされた関数への依存がなくなります。したがって、GCC と Clang の両方でコンパイルできます。
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->compar)(aa, bb, ss->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, &tmp, &cmp_switch);
#elif (defined _WIN32 || defined _WIN64 || defined __WINDOWS__)
SortStruct tmp = {arg, compar};
qsort_s(*base, nel, width, &cmp_switch, &tmp);
#else
#error Cannot detect operating system
#endif
}
注: 多くのプラットフォームでこれをテストしていないため、バグが見つかった場合はお知らせください。お使いのマシンでは機能しません。
使用例として、選択した回答と同じ並べ替えを実装しました。
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 < inv_start || *a > inv_end || *b < inv_start || *b > 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);