我认为您的选项 A 更简洁,并且会以更明智的方式扩展。想象一下当其中一个结构中的数组变大时必须realloc 空间:在选项A 中,您可以realloc 该内存,因为它在逻辑上没有附加到任何其他东西。在选项 B 中,您需要添加额外的逻辑以确保不会破坏其他数组。
我也认为(即使在 C89 中,但我可能是错的)这并没有错:
struct1 *s1 = malloc(sizeof(struct1));
s1->array1 = malloc(sizeof(uint16) * n1));
s1->array2 = malloc(sizeof(uint16) * n2));
s1->n = n1;
上面取出了中间人数组。我认为它更干净,因为您立即看到您正在为结构中的指针分配空间。
我之前将您的选项 B 用于 2D 数组,我只分配一个空间并在我的代码中使用逻辑规则将其用作 2D 空间。当我希望它是一个矩形 2D 空间时,这很有用,所以当我增加它时,我总是增加每一行或每一列。换句话说,我永远不想拥有异构数组大小。
更新:'数组的大小永远不会改变'
因为您澄清了您的结构/数组永远不需要重新分配,我认为选项 B 不太糟糕。对于这个应用程序,它似乎仍然是比选项 A 更糟糕的解决方案,以下是我这么认为的原因:
-
malloc 进行了优化,因此与单独分配空间相比,分配单个空间不会有太多优化。
- 其他工程师查看并立即理解您的代码的能力会降低。需要明确的是,任何有能力的软件工程师都应该能够查看选项 B 并弄清楚代码的编写者在做什么,但这很可能会浪费工程师的大脑周期,并可能导致初级工程师误解代码并创建一个错误。
因此,如果您对代码进行彻底的注释,并且您的应用程序绝对需要您尽可能优化所有内容,代价是干净且逻辑合理的代码(其中内存空间和数据结构以类似的方式在逻辑上分离),而且您知道这种优化比一个好的编译器(如 Clang)可以做的更好,那么选项 B 可能是一个更好的选择。
更新:测试
本着自我批评的精神,我想看看我是否可以评估差异。所以我写了两个程序(一个用于选项 A,一个用于选项 B)并在关闭优化的情况下编译它们。我使用了 FreeBSD 虚拟机来尽可能清洁环境,我使用了gcc。
这是我用来测试这两种方法的程序:
选项A.c:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define NSIZE 100000
#define NTESTS 10000000
struct test_struct {
int n;
int *array1;
int *array2;
};
void freeA(struct test_struct *input) {
free(input->array1);
free(input->array2);
free(input);
return;
}
void optionA() {
struct test_struct *s1 = malloc(sizeof(*s1));
s1->array1 = malloc(sizeof(*(s1->array1)) * NSIZE);
s1->array2 = malloc(sizeof(*(s1->array1)) * NSIZE);
s1->n = NSIZE;
freeA(s1);
s1 = 0;
return;
}
int main() {
clock_t beginA = clock();
int i;
for (i=0; i<NTESTS; i++) {
optionA();
}
clock_t endA = clock();
int time_spent_A = (endA - beginA);
printf("Time spent for option A: %d\n", time_spent_A);
return 0;
}
选项B.c:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define NSIZE 100000
#define NTESTS 10000000
struct test_struct {
int n;
int *array1;
int *array2;
};
void freeB(struct test_struct *input) {
free(input);
return;
}
void optionB() {
struct test_struct *s1 = malloc(sizeof(*s1) + 2*NSIZE*sizeof(*(s1->array1)));
s1->array1 = s1 + sizeof(*s1);
s1->array2 = s1 + sizeof(*s1) + NSIZE*sizeof(*(s1->array1));
s1->n = NSIZE;
freeB(s1);
s1 = 0;
return;
}
int main() {
clock_t beginB = clock();
int i;
for (i=0; i<NTESTS; i++) {
optionB();
}
clock_t endB = clock();
int time_spent_B = (endB - beginB);
printf("Time spent for option B: %d\n", time_spent_B);
return 0;
}
这些测试的结果以时钟为单位(请参阅clock(3) 了解更多信息)。
Series | Option A | Option B
------------------------------
1 | 332 | 158
------------------------------
2 | 334 | 155
------------------------------
3 | 334 | 156
------------------------------
4 | 333 | 154
------------------------------
5 | 339 | 156
------------------------------
6 | 334 | 155
------------------------------
avg | 336.0 | 155.7
------------------------------
请注意,这些速度仍然非常快,并且在数百万次测试中转换为毫秒。我还发现 Clang (cc) 在优化方面优于 gcc。在我的机器上,即使在编写了一个将数据写入数组的方法之后(以确保它们不会被优化而不再存在),在使用 cc 编译时,这两种方法之间也没有区别。