【问题标题】:initializing structure using macros使用宏初始化结构
【发布时间】:2018-12-19 08:34:20
【问题描述】:

我有一个结构,我正在使用预处理宏来填充结构中的数组。

#include <stdio.h>
void init_data();
typedef struct _abc{
        int a[10][10];
        int b[5][5];
}abc;
static abc q_abc[]= {
                #define XYZ(x,y,z) [x]={.a[y][z]=1,.b[y][z]=1},
                 XYZ(1,2,3)
                 XYZ(1,3,2)

};
static abc q_abc1[5];
void init_data()
{
 #define XYZW(x,y,z) q_abc1[x].a[y][z] =1;
  XYZW(1,2,3)
  XYZW(1,3,2)
}
int main()
{
        printf("\n  %d  %d\n",q_abc[1].a[2][3]);
        init_data();
        printf("\n %d  %d\n",q_abc1[1].a[2][3]);
        return 0;
}

我正在使用宏初始化结构q_abc。但这里的问题是在宏调用XYZ(1,2,3) 期间设置的值在调用下一个宏调用XYZ(1,3,2) 期间重置为默认值0。我可以理解为不指定任何显式初始化程序会将数组设置为默认值 0。

为了避免这种情况,我使用了init_data 方法。这里我不是在初始化数组,而是在分配,因此数组将包含所有宏调用的所有值。但是这里的问题是,如果数据很大或宏调用的数量很大,则 func 调用将花费很少的时间来完成,这会增加我的 exe 运行时间的开销。

有没有办法在变量定义过程中实现init_data 的行为?有什么建议吗?

【问题讨论】:

  • 我对在 {} 中使用 #define 抱有迷信的怀疑态度。您将它们放在那里的预期效果是什么?
  • 转储#define。把它写下来 - 让它一开始就可读。
  • 我不太明白你在说什么,我的意图是把#define XYZ(x,y,z) .. 表示这个宏只是并且只用于初始化这个结构(在其中定义)并且我打算包含一个包含所有宏定义 X(1,2,3).. 的头文件,依此类推。这只是我打算在更大的工作项目中使用的概念。
  • @CodeTry:由于您提到“巨大的数组”,一种方法可能是编写一个脚本,该脚本将在构建期间为您生成具有适当数据的源(甚至是一次性调用)。这比手动编写数百个数字更有效,更不容易出错。
  • 我同意,到目前为止,我所做的是编写一个 python 脚本来解析数据以转储到 Xmacro 格式的头文件 x(1,2,3,...) 。然后我试图在预处理期间加载我的数组。我只添加了一个示例代码来突出显示确切的问题,但是正如 StoryTeller 告诉我的那样,它对时间的影响并不大。

标签: c struct c-preprocessor


【解决方案1】:

在这种情况下,打开警告会对您有所帮助。用 GCC 编译你的代码给了我这个:

main.cpp:8:40: warning: initialized field overwritten [-Woverride-init]
                 #define XYZ(x,y,z) [x]={.a[y][z]=1,.b[y][z]=1},
                                        ^
main.cpp:10:18: note: in expansion of macro 'XYZ'
                  XYZ(1,3,2)
                  ^~~
main.cpp:8:40: note: (near initialization for 'q_abc[1]')
                 #define XYZ(x,y,z) [x]={.a[y][z]=1,.b[y][z]=1},
                                        ^
main.cpp:10:18: note: in expansion of macro 'XYZ'
                  XYZ(1,3,2)

而且有充分的理由。大括号初始化器将初始化所有字段,即使您省略了一些显式初始化器(那些将为零)。通过编写X(1,..) X(1,...),您可以两次初始化相同的索引。你不能像你尝试的那样把它分成两个宏扩展。如果您真的想使用宏,它必须在一个宏中。

就个人而言,我不会对宏感兴趣。指定的初始化器使代码具有足够的可读性,即使没有将它们隐藏在宏后面。

【讨论】:

  • 谢谢,我已经知道它们变为零的原因了。我想问一下是否有任何宏技巧可以消除这种情况,以便它不会将零放在那里,而是放在前面的宏调用中的最后一个值。
  • @CodeTry - 这是一个你不想进入的兔子洞。老实说,成本/收益比不值得让预处理器这样做。
  • 好的,知道了。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2019-07-17
  • 2020-10-03
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 2020-02-23
相关资源
最近更新 更多