【问题标题】:How to initialize an array of structures with variable index如何初始化具有变量索引的结构数组
【发布时间】:2014-08-08 05:58:56
【问题描述】:

我有如下结构

typedef struct
{
    int a;
    int b;
    int c;
} my_struct;

在另一个文件中,我声明了一个 my_struct 类型的变量,如下所示。

my_struct strct_arr[MAX];

其中MAX 是一个宏,它是一个可配置的值,是 18 的倍数(18 或 36 或 54 等等。它可能会上升到 18*n 次)。

我必须用 {0xff,0,0} 初始化结构。那么,如何使用我的初始值在不使用任何循环的情况下初始化整个结构数组 my_struct strct_arr[MAX];

我期望输出如下:

my_struct strct_arr[MAX]={
    {0xff,0,0},
    {0xff,0,0},
    {0xff,0,0},
    {0xff,0,0},
    …
};

但是不知道MAX的值,怎么初始化呢?

【问题讨论】:

标签: c arrays struct


【解决方案1】:

为此有 GCC 扩展。试试这个

#define MAX 18
my_struct strct_arr[MAX]={ [0 ... (MAX - 1)] = {0xff,0,0}};

查看https://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Designated-Inits.html

【讨论】:

    【解决方案2】:

    嗯,标准 C 中没有直接和直接的语法来指定一个可以做你想做的事情的初始化程序。如果你想用零初始化整个东西,那么= { 0 } 将不管大小,但0xff 使它成为一个完全不同的故事。 GCC 编译器支持在这种情况下工作的非标准扩展(有关详细信息,请参阅 Sanket Parmar 的答案),但可惜它不是标准的。

    还有一个非标准的memcpy hack,有时用于用重复模式填充内存区域。在你的情况下,它看起来如下

    my_struct strct_arr[MAX] = { { 0xff, 0, 0 } };
    memcpy(strct_arr + 1, strct_arr, sizeof strct_arr - sizeof *strct_arr);
    

    但这是一个 hack,因为它依赖于 memcpy 以逐字节方式和严格从左到右的方向进行复制(即从较小的内存地址到较大的内存地址)。但是,语言规范不能保证这一点。如果你想“合法化”这个技巧,你必须编写你自己的my_memcpy 版本,专门以这种方式工作(逐字节,从左到右)并改用它。当然,这在形式上是一个不完全基于初始化器语法的循环解决方案。

    【讨论】:

    • 即使这个 memcpy “有效”,那也是因为 memcpy 的实现中有一个循环,因此通过在自己的代码中显式放置循环,您不会损失任何性能。
    【解决方案3】:

    是的,这可以使用 C 预处理器!

    #include <stdio.h>
    #include <boost/preprocessor/repetition/repeat.hpp>
    
    #define INITS(z, n, t) { 0xFF, 0, 0 },
    #define REP(item, n) BOOST_PP_REPEAT(n, INITS, item)
    
    #define MAX 123
    
    typedef struct { int a,b,c; } my_struct;
    
    my_struct ms[] = { REP(, MAX) };
    
    int main()
    {
        // Check it worked
        printf("%d\n", (int)(sizeof ms / sizeof *ms));
    }
    

    注意:boost 是一个 C++ 包,但是 boost/preprocessor 只使用两种语言共有的预处理器功能。如果你的实现默认不允许这个#include,你可以从boost源代码中找到repeat.hpp的副本。

    另外,BOOST_PP_REPEAT 默认最大为256。如果您的MAX 大于此值,您可以编辑repeat.hpp 以允许更大的值,从那里做什么应该很明显。

    注意:this post 描述了一个递归宏系统,它不需要与 repeat.hpp 使用的相同类型的实现,但我无法让它工作。

    信用:this post

    【讨论】:

    • 我知道必须有一个预处理器解决方案。问题始于#define MAX *something*;预处理器中出现的问题。解决方案也必须来自那里。 ;) 正如我所怀疑的那样,它令人讨厌(但我无法移开视线)! +1 不让我失望。 :)
    【解决方案4】:

    只是为了多样化,因为你知道数组将是 18 的倍数,你可以使用这样的东西:

    #define INIT_X_1     { 0xff, 0, 0 }
    #define INIT_X_3     INIT_X_1, INIT_X_1, INIT_X_1
    #define INIT_X_9     INIT_X_3, INIT_X_3, INIT_X_3
    #define INIT_X_18    INIT_X_9, INIT_X_9
    
    my_struct strct_arr[MAX] =
    {
        INIT_X_18,
    #if MAX > 18
        INIT_X_18,
    #if MAX > 36
        INIT_X_18,
    #endif
    #endif
    };
    

    这无需 C99 支持(甚至可以与标准 C 一起使用)、GCC 扩展或 Boost 预处理器库即可工作。在其他所有方面,其他解决方案都更好。

    【讨论】:

    • 我看到您已经考虑了多达 54 次。恐怕如果我的数组大小是 64,它会用结构值初始化 64 次吗?如果我需要继续达到最大值(这是一个可配置的值),您能否提供任何可能性?
    • 使用我的解决方案中的wildplassergeneralization,只要你有一个上限即可。否则,您将需要使用一种额外的语言机制,例如您在他的答案下方的 cmets 中提到的。我根据您在问题中提到的 18 的倍数量身定制了答案。如果做不到这一点,请考虑使用单个初始化程序并在运行时将其复制到您的数组中。与您要做的所有其他事情相比,它不会花费很长时间。
    【解决方案5】:

    转述Jonathan Lefflersolution

    struct my_struct { char c, int a; int b; }
    
    #define MAX 135
    
    #define INIT_X_1     { 0xff, 0, 0 }
    #define INIT_X_2     INIT_X_1, INIT_X_1
    #define INIT_X_4     INIT_X_2, INIT_X_2
    #define INIT_X_8     INIT_X_4, INIT_X_4
    #define INIT_X_16    INIT_X_8, INIT_X_8
    #define INIT_X_32    INIT_X_16, INIT_X_16
    #define INIT_X_64    INIT_X_32, INIT_X_32
    #define INIT_X_128   INIT_X_64, INIT_X_64
    
    struct my_struct strct_arr[MAX] =
    {
    #if (MAX & 1)
        INIT_X_1,
    #endif
    #if (MAX & 2)
        INIT_X_2,
    #endif
    #if (MAX & 4)
        INIT_X_4,
    #endif
    #if (MAX & 8)
        INIT_X_8,
    #endif
    #if (MAX & 16)
        INIT_X_16,
    #endif
    #if (MAX & 32)
        INIT_X_32,
    #endif
    #if (MAX & 64)
        INIT_X_64,
    #endif
    #if (MAX & 128)
        INIT_X_128,
    #endif
    };
    

    【讨论】:

    • Wildplasser 先生,这是我经过一番挣扎后自己尝试的方式。但问题是,我不能将我的初始化限制为 54 或 62 甚至 128。很难了解 MAX 数值,它会因用户配置而异。因此,我创建了一个 perl 脚本,它将根据配置的 MAX 值生成一个宏。这样,我就不会在运行时给 C 代码增加负担。
    • 嗯,将这个解决方案扩展到 512、1024 等并不难。每次翻倍只会花费您几(四)行。但代码生成始终是一种选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多