C可以在编译时排序吗?
Can C sort at compile time?
在 C 中是否可以在编译时对元素进行排序?
语法是次要的,我在想这样的宏:
SORT(9, -1, 12, 4) // expands to: -1, 4, 9, 12
SORT(dog, cat, cow) // expands to: cat, cow, dog
但我不会对任何 API 皱眉,只要它在不发出单个 CPU 指令的情况下进行排序。
要求比较宽松:
- 纯 C,无 C++。保持在 C 标准内会很好,但建立语言扩展是公平的游戏。
- 编译器是唯一允许的工具。 Unix
sort
或自制代码生成器不受欢迎,因为它们会使构建步骤复杂化。
- 任何元素类型都可以。如果它可以排序就可以了,例如数字而不是字符串。
- 固定长度API可以。必须调用
SORT_5
才能对 5 个元素进行排序。
我意识到解决方案可能会求助于一些勉强编译的语言巫术,我只是想知道这是否可能。
这里有一个宏方法:
#define GET_1_of_3(a, b, c) ((a) < (b) ? ((c) < (a) ? (c) : (a)) : ((c) < (b) ? (c) : (b)))
#define GET_2_of_3(a, b, c) ((c) > (a) && (c) < (b) || (c) < (a) && (c) > (b) ? (c) : ((b) > (a) && (b) < (c) || (b) < (a) && (b) > (c) ? (b) : (a)))
#define GET_3_of_3(a, b, c) ((a) > (b) ? ((c) > (a) ? (c) : (a)) : ((c) > (b) ? (c) : (b)))
#define SORT_3(a, b, c) GET_1_of_3(a, b, c),GET_2_of_3(a, b, c),GET_3_of_3(a, b, c)
void main(){
int x[3] = { SORT_3(6,2,3) };
printf("%d, %d, %d", x[0], x[1], x[2]);
}
这适用于 int
并适用于 C,但对于没有来自 C++ 的 const_expr
的字符串是不可能的。很明显,你是在为大量的宏写支持大量的SORT_X
.
让我们考虑对只能为0或1的数字进行排序。对于两个数字,以下代码中的SORT2
可以对它们进行排序:
#define SORT2(a,b) SORT2_##a##b
#define SORT2_00 0,0
#define SORT2_01 0,1
#define SORT2_10 0,1
#define SORT2_11 1,1
这当然可以扩展到更大的范围和更多的参数。
实际上,您不能在编译时在 C 中排序(至少如果您想对足够多的编译时常量整数进行排序;在这种情况下,有 300 个宏或函数名为 SORT_1
, SORT_2
, ... SORT_300
是不实用的,除非你生成这些你不想生成的函数或宏),但是....
实用的方法是使用您自己的或其他一些预处理器(例如 gpp)并让它进行排序。或者简单地说,在一些包含的文件中包含数字并生成 排序的 文件(例如,使用 awk
& sort
的 make
规则)
您还可以考虑使用 link-time-optimization to an LTO-compiled libc 链接,使用其 LTO 优化的 qsort
。这不常见,AFAIK,并且您无法保证编译器足够智能以内联您的 LTO qsort
等...(AFAIK,当前的 C 编译器不这样做)。
如果使用最近的 GCC (4.8, 4.9 or soon 5.0 in march 2015), you could customize it (e.g. with MELT 或您自己的 C++ 插件进行编译)来定义您的 __builtin_my_compile_time_sort
(或者可能是某些 _Pragma
)来完成这项工作。这是特定于编译器的(可能意味着几天的工作,除非你已经知道 MELT)
最简单的事情就是接受稍微复杂化的构建步骤。没什么大不了的。
在 C 中是否可以在编译时对元素进行排序?
语法是次要的,我在想这样的宏:
SORT(9, -1, 12, 4) // expands to: -1, 4, 9, 12
SORT(dog, cat, cow) // expands to: cat, cow, dog
但我不会对任何 API 皱眉,只要它在不发出单个 CPU 指令的情况下进行排序。
要求比较宽松:
- 纯 C,无 C++。保持在 C 标准内会很好,但建立语言扩展是公平的游戏。
- 编译器是唯一允许的工具。 Unix
sort
或自制代码生成器不受欢迎,因为它们会使构建步骤复杂化。 - 任何元素类型都可以。如果它可以排序就可以了,例如数字而不是字符串。
- 固定长度API可以。必须调用
SORT_5
才能对 5 个元素进行排序。
我意识到解决方案可能会求助于一些勉强编译的语言巫术,我只是想知道这是否可能。
这里有一个宏方法:
#define GET_1_of_3(a, b, c) ((a) < (b) ? ((c) < (a) ? (c) : (a)) : ((c) < (b) ? (c) : (b)))
#define GET_2_of_3(a, b, c) ((c) > (a) && (c) < (b) || (c) < (a) && (c) > (b) ? (c) : ((b) > (a) && (b) < (c) || (b) < (a) && (b) > (c) ? (b) : (a)))
#define GET_3_of_3(a, b, c) ((a) > (b) ? ((c) > (a) ? (c) : (a)) : ((c) > (b) ? (c) : (b)))
#define SORT_3(a, b, c) GET_1_of_3(a, b, c),GET_2_of_3(a, b, c),GET_3_of_3(a, b, c)
void main(){
int x[3] = { SORT_3(6,2,3) };
printf("%d, %d, %d", x[0], x[1], x[2]);
}
这适用于 int
并适用于 C,但对于没有来自 C++ 的 const_expr
的字符串是不可能的。很明显,你是在为大量的宏写支持大量的SORT_X
.
让我们考虑对只能为0或1的数字进行排序。对于两个数字,以下代码中的SORT2
可以对它们进行排序:
#define SORT2(a,b) SORT2_##a##b
#define SORT2_00 0,0
#define SORT2_01 0,1
#define SORT2_10 0,1
#define SORT2_11 1,1
这当然可以扩展到更大的范围和更多的参数。
实际上,您不能在编译时在 C 中排序(至少如果您想对足够多的编译时常量整数进行排序;在这种情况下,有 300 个宏或函数名为 SORT_1
, SORT_2
, ... SORT_300
是不实用的,除非你生成这些你不想生成的函数或宏),但是....
实用的方法是使用您自己的或其他一些预处理器(例如 gpp)并让它进行排序。或者简单地说,在一些包含的文件中包含数字并生成 排序的 文件(例如,使用 awk
& sort
的 make
规则)
您还可以考虑使用 link-time-optimization to an LTO-compiled libc 链接,使用其 LTO 优化的 qsort
。这不常见,AFAIK,并且您无法保证编译器足够智能以内联您的 LTO qsort
等...(AFAIK,当前的 C 编译器不这样做)。
如果使用最近的 GCC (4.8, 4.9 or soon 5.0 in march 2015), you could customize it (e.g. with MELT 或您自己的 C++ 插件进行编译)来定义您的 __builtin_my_compile_time_sort
(或者可能是某些 _Pragma
)来完成这项工作。这是特定于编译器的(可能意味着几天的工作,除非你已经知道 MELT)
最简单的事情就是接受稍微复杂化的构建步骤。没什么大不了的。