gpt4 book ai didi

C - 实现将许多元素快速推送到数组末尾

转载 作者:太空狗 更新时间:2023-10-29 16:32:05 26 4
gpt4 key购买 nike

我有一个简单的结构来保存一个数组:

struct array_of_a_type {
size_t allocated_size;
size_t elements; /* 1-index based */
a_type *array;
};

我想写一个简单的函数,像这样:

bool simple_function(struct array_of_a_type *my_array, int a, int b, int c, int d)
{
a_type new_chunk[] = {
a, b, a+b, d, c,
c, c, c+d, b+d, a,
a+c, b+c, c+d, c+d, c,
};
size_t size = sizeof(new_chunk) / sizeof(a_type);
return push_to_array(my_array, new_chunk, size);
}

my_array 是一个静态的全局变量。下面是 push_to_array 的实现。

static bool push_to_array(struct array_of_a_type *a, a_type *new_chunk, size_t size)
{
const size_t new_size = a->elements + size;
const size_t old_size = a->elements;
if (new_size > a->allocated_size) {
/* The allocated_size is most of the time big enough.
I’ve stripped this part of code to minimum. */
a_type *tmp = realloc(a->array, new_size * sizeof(a_type));
if (!tmp) {
return true;
} else {
a->array = tmp;
a->allocated_size = new_size;
}
}
a->elements = new_size;
memcpy(a->array + old_size, new_chunk, size * sizeof(a_type));
return false;
}

我的问题:
我如何重写“simple_function”以使更多编译器生成将直接写入目标的代码?我希望代码保持简短和灵活。

我的代码有效。不幸的是,gcc(和旧的 clang)在堆栈上创建临时数据,然后将其复制到目的地。下面是生成的 x86_64 汇编程序的片段。

movq    8(%rsp), %rdx
movq %rdx, 8(%rax)
movq 16(%rsp), %rdx
movq %rdx, 16(%rax)
movq 24(%rsp), %rdx
movq %rdx, 24(%rax)
movq 32(%rsp), %rdx
movq %rdx, 32(%rax)

对于 AMD,汇编器有这个:

rep movsq

新的 clang 工作正常。我用 -O3 编译。

我试过一次添加一个元素的代码。不幸的是,有很多条件跳转调用 realloc。

最佳答案

为了提高效率,您需要分离增长数组的逻辑,并将值分配给(未使用的)槽,以避免额外的副本(从堆栈到数组)。

为了美化代码,您可以创建一组辅助宏。我假设“推”是指“附加到数组”。如果您的意思真的是“前置”,那么还需要一个额外的 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 个。根据您使用的编译器,您可以扩展宏以支持更大数量的参数,但其他编译器可能会因此而窒息。

关于C - 实现将许多元素快速推送到数组末尾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29725670/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com