为了提高效率,您需要分离增长数组的逻辑,并将值分配给(未使用的)插槽,以避免额外的复制(从堆栈到数组)。
为了美化代码,您可以创建一组帮助宏。我假设“推”是指“附加到数组”。如果您的真正意思是“前置”,那么还需要一个额外的 memmove()。
假设你有
#include <stdlib.h>
#include <stdio.h>
typedef int array_data_type;
typedef struct {
size_t size;
size_t used;
array_data_type *item;
} array_type;
#define ARRAY_INITIALIZER { 0, 0, NULL }
void array_free(array_type *const array)
{
free(array->item);
array->size = 0;
array->used = 0;
array->item = NULL;
}
void array_init(array_type *const array)
{
array->size = 0;
array->used = 0;
array->item = NULL;
}
void array_init_size(array_type *const array, const size_t size)
{
if (!size) {
array->size = 0;
array->used = 0;
array->item = NULL;
return;
}
array->item = malloc(size * sizeof array->item[0]);
if (!array->item) {
fprintf(stderr, "array_init_size(%p, %zu): Out of memory.\n", (void *)array, size);
exit(EXIT_FAILURE);
}
array->size = size;
array->used = 0;
}
void array_grow_to(array_type *const array, size_t size)
{
array_data_type *temp;
if (size < 4)
size = 4;
else
if (size < 16777216) {
size |= size >> 1;
size |= size >> 2;
size |= size >> 4;
size |= size >> 8;
size |= size >> 16;
size++;
} else
size = (size | 8388607) + 8388609;
temp = realloc(array->item, size * sizeof array->item[0]);
if (!temp) {
fprintf(stderr, "array_grow_to(%p, %zu): Out of memory.\n", (void *)array, size);
exit(EXIT_FAILURE);
}
array->item = temp;
array->size = size;
}
static inline array_data_type *array_grow_by(array_type *const array, size_t const count)
{
array_data_type *retval;
if (array->used + count > array->size)
array_grow_to(array, array->used + count);
retval = array->item + array->used;
array->used += count;
return retval;
}
我喜欢使用used 表示数组中的元素数量,使用size 表示数组分配了内存的元素数量。如果您习惯了其他名称,请进行搜索和替换。
array_grow_to() 将新大小调整为至少 4,或者如果小于 16,777,216,则调整为 2 的下一个幂,或者调整为 8,388,608 的更大倍数。这限制了非常大的列表的已分配但未使用的内存量。
array_grow_by() 确保数组有空间容纳count 新元素,并返回指向第一个未使用的新元素的指针。
如果您定义以下 C99 预处理器宏,
#define MACRO_CONCATENATE(part1, ...) part1 ## __VA_ARGS__
#define ARRAY_SET_N(array, count, ...) MACRO_CONCATENATE(ARRAY_SET_, count)(array, count, __VA_ARGS__)
#define ARRAY_SET_0(...)
#define ARRAY_SET_1(a, n, v) a[n-1] = v
#define ARRAY_SET_2(a, n, v, ...) a[n-2] = v; ARRAY_SET_1(a, n, __VA_ARGS__)
#define ARRAY_SET_3(a, n, v, ...) a[n-3] = v; ARRAY_SET_2(a, n, __VA_ARGS__)
#define ARRAY_SET_4(a, n, v, ...) a[n-4] = v; ARRAY_SET_3(a, n, __VA_ARGS__)
#define ARRAY_SET_5(a, n, v, ...) a[n-5] = v; ARRAY_SET_4(a, n, __VA_ARGS__)
#define ARRAY_SET_6(a, n, v, ...) a[n-6] = v; ARRAY_SET_5(a, n, __VA_ARGS__)
#define ARRAY_SET_7(a, n, v, ...) a[n-7] = v; ARRAY_SET_6(a, n, __VA_ARGS__)
#define ARRAY_SET_8(a, n, v, ...) a[n-8] = v; ARRAY_SET_7(a, n, __VA_ARGS__)
#define ARRAY_SET_9(a, n, v, ...) a[n-9] = v; ARRAY_SET_8(a, n, __VA_ARGS__)
#define ARRAY_SET_10(a, n, v, ...) a[n-10] = v; ARRAY_SET_9(a, n, __VA_ARGS__)
#define ARRAY_SET_11(a, n, v, ...) a[n-11] = v; ARRAY_SET_10(a, n, __VA_ARGS__)
#define ARRAY_SET_12(a, n, v, ...) a[n-12] = v; ARRAY_SET_11(a, n, __VA_ARGS__)
#define ARRAY_SET_13(a, n, v, ...) a[n-13] = v; ARRAY_SET_12(a, n, __VA_ARGS__)
#define ARRAY_SET_14(a, n, v, ...) a[n-14] = v; ARRAY_SET_13(a, n, __VA_ARGS__)
#define ARRAY_SET_15(a, n, v, ...) a[n-15] = v; ARRAY_SET_14(a, n, __VA_ARGS__)
#define ARRAY_SET_16(a, n, v, ...) a[n-16] = v; ARRAY_SET_15(a, n, __VA_ARGS__)
#define ARRAY_SET_17(a, n, v, ...) a[n-17] = v; ARRAY_SET_16(a, n, __VA_ARGS__)
#define ARRAY_SET_18(a, n, v, ...) a[n-18] = v; ARRAY_SET_17(a, n, __VA_ARGS__)
#define ARRAY_SET_19(a, n, v, ...) a[n-19] = v; ARRAY_SET_18(a, n, __VA_ARGS__)
#define ARRAY_SET_20(a, n, v, ...) a[n-20] = v; ARRAY_SET_19(a, n, __VA_ARGS__)
#define ARRAY_SET_21(a, n, v, ...) a[n-21] = v; ARRAY_SET_20(a, n, __VA_ARGS__)
#define ARRAY_SET_22(a, n, v, ...) a[n-22] = v; ARRAY_SET_21(a, n, __VA_ARGS__)
#define ARRAY_SET_23(a, n, v, ...) a[n-23] = v; ARRAY_SET_22(a, n, __VA_ARGS__)
#define ARRAY_SET_24(a, n, v, ...) a[n-24] = v; ARRAY_SET_23(a, n, __VA_ARGS__)
#define ARRAY_SET_25(a, n, v, ...) a[n-25] = v; ARRAY_SET_24(a, n, __VA_ARGS__)
#define ARRAY_SET_26(a, n, v, ...) a[n-26] = v; ARRAY_SET_25(a, n, __VA_ARGS__)
#define ARRAY_SET_27(a, n, v, ...) a[n-27] = v; ARRAY_SET_26(a, n, __VA_ARGS__)
#define ARRAY_SET_28(a, n, v, ...) a[n-28] = v; ARRAY_SET_27(a, n, __VA_ARGS__)
#define ARRAY_SET_29(a, n, v, ...) a[n-29] = v; ARRAY_SET_28(a, n, __VA_ARGS__)
#define ARRAY_SET_30(a, n, v, ...) a[n-30] = v; ARRAY_SET_29(a, n, __VA_ARGS__)
#define ARRAY_SET_31(a, n, v, ...) a[n-31] = v; ARRAY_SET_30(a, n, __VA_ARGS__)
#define ARRAY_SET_32(a, n, v, ...) a[n-32] = v; ARRAY_SET_31(a, n, __VA_ARGS__)
#define ARRAY_SET_33(a, n, v, ...) a[n-33] = v; ARRAY_SET_32(a, n, __VA_ARGS__)
#define ARRAY_SET_34(a, n, v, ...) a[n-34] = v; ARRAY_SET_33(a, n, __VA_ARGS__)
#define ARRAY_SET_35(a, n, v, ...) a[n-35] = v; ARRAY_SET_34(a, n, __VA_ARGS__)
#define ARRAY_SET_36(a, n, v, ...) a[n-36] = v; ARRAY_SET_35(a, n, __VA_ARGS__)
#define ARRAY_SET_37(a, n, v, ...) a[n-37] = v; ARRAY_SET_36(a, n, __VA_ARGS__)
#define ARRAY_SET_38(a, n, v, ...) a[n-38] = v; ARRAY_SET_37(a, n, __VA_ARGS__)
#define ARRAY_SET_39(a, n, v, ...) a[n-39] = v; ARRAY_SET_38(a, n, __VA_ARGS__)
#define ARRAY_SET_40(a, n, v, ...) a[n-40] = v; ARRAY_SET_39(a, n, __VA_ARGS__)
#define ARRAY_SET_41(a, n, v, ...) a[n-41] = v; ARRAY_SET_40(a, n, __VA_ARGS__)
#define ARRAY_SET_42(a, n, v, ...) a[n-42] = v; ARRAY_SET_41(a, n, __VA_ARGS__)
#define ARRAY_SET_43(a, n, v, ...) a[n-43] = v; ARRAY_SET_42(a, n, __VA_ARGS__)
#define ARRAY_SET_44(a, n, v, ...) a[n-44] = v; ARRAY_SET_43(a, n, __VA_ARGS__)
#define ARRAY_SET_45(a, n, v, ...) a[n-45] = v; ARRAY_SET_44(a, n, __VA_ARGS__)
#define ARRAY_SET_46(a, n, v, ...) a[n-46] = v; ARRAY_SET_45(a, n, __VA_ARGS__)
#define ARRAY_SET_47(a, n, v, ...) a[n-47] = v; ARRAY_SET_46(a, n, __VA_ARGS__)
#define ARRAY_SET_48(a, n, v, ...) a[n-48] = v; ARRAY_SET_47(a, n, __VA_ARGS__)
#define ARRAY_SET_49(a, n, v, ...) a[n-49] = v; ARRAY_SET_48(a, n, __VA_ARGS__)
#define ARRAY_SET_50(a, n, v, ...) a[n-50] = v; ARRAY_SET_49(a, n, __VA_ARGS__)
#define ARRAY_SET_51(a, n, v, ...) a[n-51] = v; ARRAY_SET_50(a, n, __VA_ARGS__)
#define ARRAY_SET_52(a, n, v, ...) a[n-52] = v; ARRAY_SET_51(a, n, __VA_ARGS__)
#define ARRAY_SET_53(a, n, v, ...) a[n-53] = v; ARRAY_SET_52(a, n, __VA_ARGS__)
#define ARRAY_SET_54(a, n, v, ...) a[n-54] = v; ARRAY_SET_53(a, n, __VA_ARGS__)
#define ARRAY_SET_55(a, n, v, ...) a[n-55] = v; ARRAY_SET_54(a, n, __VA_ARGS__)
#define ARRAY_SET_56(a, n, v, ...) a[n-56] = v; ARRAY_SET_55(a, n, __VA_ARGS__)
#define ARRAY_SET_57(a, n, v, ...) a[n-57] = v; ARRAY_SET_56(a, n, __VA_ARGS__)
#define ARRAY_SET_58(a, n, v, ...) a[n-58] = v; ARRAY_SET_57(a, n, __VA_ARGS__)
#define ARRAY_SET_59(a, n, v, ...) a[n-59] = v; ARRAY_SET_58(a, n, __VA_ARGS__)
#define ARRAY_SET_60(a, n, v, ...) a[n-60] = v; ARRAY_SET_59(a, n, __VA_ARGS__)
#define ARRAY_SET_61(a, n, v, ...) a[n-61] = v; ARRAY_SET_60(a, n, __VA_ARGS__)
#define ARRAY_SET_62(a, n, v, ...) a[n-62] = v; ARRAY_SET_61(a, n, __VA_ARGS__)
#define ARRAY_SET_63(a, n, v, ...) a[n-63] = v; ARRAY_SET_62(a, n, __VA_ARGS__)
#define ARRAY_SET_64(a, n, v, ...) a[n-64] = v; ARRAY_SET_63(a, n, __VA_ARGS__)
#define ARRAY_APPEND_N(array, count, ...) \
do { \
array_data_type *const _base = array_grow_by(array, count); \
ARRAY_SET_N(_base, count, __VA_ARGS__); \
} while(0)
然后你可以把你的简单函数写成
void simple_function(array_type *array,
const array_data_type a, const array_data_type b,
const array_data_type c, const array_data_type d)
{
ARRAY_APPEND_N(array, 15, a, b, a+b, d, c,
c, c, c+d, b+d, a,
a+c, b+c, c+d, c+d, c);
}
并将其预处理为(缩进除外)
void simple_function(array_type *array,
const array_data_type a, const array_data_type b,
const array_data_type c, const array_data_type d)
{
do {
array_data_type *const _base = array_grow_by(array, 15);
_base[15 - 15] = a;
_base[15 - 14] = b;
_base[15 - 13] = a+b;
_base[15 - 12] = d;
_base[15 - 11] = c;
_base[15 - 10] = c;
_base[15 - 9] = c;
_base[15 - 8] = c+d;
_base[15 - 7] = b+d;
_base[15 - 6] = a;
_base[15 - 5] = a+c;
_base[15 - 4] = b+c;
_base[15 - 3] = c+d;
_base[15 - 2] = c+d;
_base[15 - 1] = c;
} while(0);
}
通常可以在 Intel/AMD64 架构(以及其他支持相对寻址模式的架构)上编译为出色的机器代码。在其他一些架构上,最好不要将 _base 设为常量,而是自动递增 (*(_base++) = v;)。
如果你实现了一个PP_NARG()宏来统计宏参数的个数,你可以添加宏
#define ARRAY_APPEND(array, ...) ARRAY_APPEND_N(array, PP_NARG(__VA_ARGS__), __VA_ARGS__)
在这种情况下,您的函数将简化为
void simple_function(array_type *array,
const array_data_type a, const array_data_type b,
const array_data_type c, const array_data_type d)
{
ARRAY_APPEND(array, a, b, a+b, d, c,
c, c, c+d, b+d, a,
a+c, b+c, c+d, c+d, c);
}
在某些编译器中,预处理器宏参数的数量限制为 64,这将单个宏可以添加的最大元素数限制为 62。根据您使用的编译器,您可以扩展宏以支持更多的参数,但其他编译器可能会对此感到窒息。