【问题标题】:Run-Time Conditional Fields in Structs in CC 结构中的运行时条件字段
【发布时间】:2014-05-08 05:59:08
【问题描述】:

我有一个用 C 语言编写的特定应用程序,需要提高内存效率。它正在收集统计信息,因此我需要能够在运行时“打开/关闭”某些字段以最小化内存消耗。 我知道您可以使用宏定义条件结构字段,但如果我没记错的话,那是编译时,有没有可能的方法在 C 中在运行时执行此操作?

例子:

输入:

collect (A,B)

会产生这样的结构:

struct statistics{
double A;
double B;
};

但输入:

collect (A,B,C)

会产生这样的结构:

struct statistics{
double A;
double B;
double C;
};

【问题讨论】:

  • 您需要使用某种动态分配和结构。
  • 在这种情况下,最好为每条记录使用动态大小的数组而不是结构(假设所有字段都是相同的类型,即double?)。或者,您可以从 AoS 切换到 SoA,其中每个数组都是一个指针,并且仅在需要时分配。
  • 对,(它们不都是双精度,主要是双精度和整数);然而,一个指针本身是 4 字节,所以我将有一个指针,而不是所有这些字段中的每一个,它可能会或可能不会被分配——但在内存中的顺序仍然大致相同。有没有可能做得比这更好?
  • 我已经将我上面的后一个建议充实到下面的更完整的答案中......

标签: c memory-management struct runtime conditional


【解决方案1】:

无法在运行时关闭结构内的某些字段。但是,您可以拥有一个指向动态分配的双精度数组的指针,该数组可以表示多个字段。 例如:

#include <stdio.h>
#include <stdlib.h>

struct stats
{
    size_t number_of_doubles;
    double* data;
};

void make_stats(struct stats* pStats)
{
    pStats->number_of_doubles = 3;
    pStats->data = (double*) malloc(pStats->number_of_doubles * sizeof(double));
}

void delete_stats(struct stats* pStats)
{
    free(pStats->data);
}

int main()
{
    struct stats foo;

    make_stats(&foo);

    foo.data[0] = 3.0;
    foo.data[1] = 5.0;
    foo.data[2] = 7.0;

    delete_stats(&foo);    
    return 0;
}

【讨论】:

  • 谢谢!我想这会起作用,我需要将 number_of_doubles 更改为某种标志,以确定某些统计数据是否存在——但我想这可行。
  • 不客气。我添加了一个 main 供您试用和删除。如果这对您有帮助,请标记为已回答:)
【解决方案2】:

没有办法在运行时改变结构的大小。每当您在堆栈或堆上分配它们时,结构的大小都会内置到可执行文件的指令中。再举一个例子,结构的sizeof 在编译时可用,因此在运行时不能更改。

当然,您可以使用带有自定义内存管理器的自定义结构来执行此操作,但它并未直接内置于语言中。

【讨论】:

    【解决方案3】:

    而不是通常的结构数组(AoS):

    struct statistics{
        double A;
        double B;
        double C;
    };
    
    struct statistics my_statistics = malloc(1000000 * sizeof(my_statistics[0]));
    
    my_statistics[0].A = 1;
    my_statistics[0].B = 2;
    my_statistics[0].C = 3;
    

    您可以切换到数组结构 (SoA):

    struct statistics{
        double *A;
        double *B;
        double *C;
    };
    
    struct statistics my_statistics;
    
    my_statistics.A = using_A ? malloc(1000000 * sizeof(my_statistics.A[0])) : NULL;
    my_statistics.B = using_B ? malloc(1000000 * sizeof(my_statistics.B[0])) : NULL;
    my_statistics.C = using_C ? malloc(1000000 * sizeof(my_statistics.C[0])) : NULL;
    
    my_statistics.A[0] = 1;
    my_statistics.B[0] = 2;
    my_statistics.C[0] = 3;
    

    【讨论】:

    • 感谢先生的示范!考虑到收集的统计信息数量超过 100,这仍然会有至少 4bytes*100 大小的结构。
    • 当然 - 我不知道您正在收集多少数据以及您的内存限制是什么,因此要给出最佳解决方案并不容易。如果内存真的紧张,那么使用动态大小的数组 - 开销略小,但代价是访问单个元素更复杂。
    • @user2662165:PS:您确实意识到在 AoS 案例中上述结构只有 一个 实例?
    • 是的,事实上,如果不是以下情况,它会很有用:我仍然需要维护一个结构数组,因为每个实例都有不同的字段,基于它需要收集的内容——所以,一个一个实例将收集 A 和 B,而另一个正在收集 A、B 和 C。因此,如果我将其实现为 SoA,它会变得更加复杂。现在,如果我像上面那样使用 AoS 并为每个实例分配一个标志以显示它正在收集什么,我将知道结构内的数据数组有多大以及哪些位置属于每个字段等等......
    猜你喜欢
    • 2016-05-08
    • 1970-01-01
    • 2013-05-31
    • 2015-03-08
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2018-01-18
    • 2015-01-11
    相关资源
    最近更新 更多