【问题标题】:error: initializer element is not constant错误:初始化元素不是常量
【发布时间】:2012-04-10 15:52:40
【问题描述】:
#include <stdio.h>

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

typedef struct {
  int x;
  int y;
  int z;
  FIRST_T *p;
} SECOND_T;

typedef struct {
  int a1;
  int a2;
  int a3;
  FIRST_T *q;
}THIRD_T;

const FIRST_T p1[]={{1,2,3},{3,4,5},{6,7,8}};
const FIRST_T p2[]={{4,5,12},{7,8,9}};
const SECOND_T my_second[]=
{
  {1,2,3,p1},
  {4,5,6,p2}
};
const THIRD_T my_third[] = {{1,2,3,my_second[1].p},{4,5,6,my_second[0].p}};

int main() {
  //const THIRD_T my_third[] = {{1,2,3,my_second[1].p},{4,5,6,my_second[0].p}};
  printf("%d %d %d %d \n", 
         my_third[0].a1,
         my_third[0].a2,
         my_third[0].a3,
         my_third[0].q[1].c);
}

我知道如果我在函数范围内初始化 my_third 它可以正常工作,因为“在 C 中,具有静态存储持续时间的对象(例如在文件范围内声明的对象)只能使用常量表达式进行初始化”,否则它会给我:

错误:初始化元素不是常量 new.c:41: 错误:(接近于 `my_third[0].q' 的初始化)

现在我的问题是:在不移动函数内部的表达式的情况下,是否有任何解决方法可供我使用。我无法移动,因为这些结构在我的代码中的许多地方都使用了。

如果您需要更多信息,请告诉我。

【问题讨论】:

  • 在将代码发布到此站点之前,您确实需要修复缩进并在 typedef 之间添加一些空行。

标签: c static structure


【解决方案1】:

一种丑陋的方式:

#include <stdio.h>

struct first_t {
    int a;
    int b;
    int c;
};

struct second_t {
    int x;
    int y;
    int z;
    const struct first_t *p;
};

struct third_t {
    int a1;
    int a2;
    int a3;
    const struct first_t *q;
};

const struct first_t p1[] = {
    {1, 2, 3},
    {3, 4, 5},
    {6, 7, 8}
};
const struct first_t p2[] = {
    {4, 5, 12},
    {7, 8, 9}
};
const struct second_t my_second[] = {
    {1, 2, 3, p1},
    {4, 5, 6, p2}
};
const struct third_t  my_third[] = {
    {1, 2, 3, (const struct first_t*)&my_second[1].p},
    {4, 5, 6, (const struct first_t*)&my_second[0].p}
};

int main(void) {
    fprintf(stdout,
        "PRNT: %d %d %d %d\n",
        my_third[0].a1,
        my_third[0].a2,
        my_third[0].a3,
        my_third[0].q[1].c
    );

    return 0;
}

给予:

/* gcc -Wall -Wextra -pedantic -std=c89 -ggdb -o bad fmts.c && ./bad
 *
 * PRNT: 1 2 3 4
 *
 * */

【讨论】:

    【解决方案2】:

    怎么样

    const THIRD_T my_third[] = {{1,2,3,p2},{4,5,6,p1}};
    

    因为这正是您将获得的价值?

    为了使更改更容易,您可以包装一个层,例如

    const FIRST_T p1[]={{1,2,3},{3,4,5},{6,7,8}};
    const FIRST_T p2[]={{4,5,12},{7,8,9}};
    
    #define first_p p1
    #define second_p p2
    
    const SECOND_T my_second[]=
    {
    {1,2,3,first_p},
    {4,5,6,second_p}
    };
    const THIRD_T my_third[] = {{1,2,3,second_p},{4,5,6,first_p}};
    

    然后只需更改#defines 以使my_second 和my_third 保持同步。

    另一种选择是将THIRD_T 更改为包含SECOND_T 而不是FIRST_T。然后(也许)有一个#define 做简化访问:

    typedef struct {
    int a1;
    int a2;
    int a3;
    SECOND_T *qq;
    }THIRD_T;
    
    #define q qq->p
    

    这样

    my_third->q
    

    变得有效

    my_third->qq->p
    

    .

    【讨论】:

      【解决方案3】:
      typedef struct {
          int x;
          int y;
          int z;
          FIRST_T *p;
      } SECOND_T;
      

      当您声明此结构const 的变量时,它的所有成员都变为const,因为它们存储在ROM 中。 int const x;、int const y; 等。对于指针,这意味着它变成了FIRST_T * const p;。也就是说,指向非常量数据的 const 指针。但是,指向的类型仍然不是const!我怀疑这就是你遇到问题的原因。

      {1,2,3,p1},
      

      p1 是数组类型,并衰减为const FIRST_T p1* const(指向常量数据的常量指针)。您尝试将其分配给FIRST_T * const p;(指向非常量数据的常量指针)。要解决此问题,请尝试将类型声明为

      typedef struct {
        int x;
        int y;
        int z;
        const FIRST_T *p;
      } SECOND_T;
      
      typedef struct {
        int a1;
        int a2;
        int a3;
        const FIRST_T *q;
      } THIRD_T;
      

      使用 MinGW、GCC 4.6.2 测试。

      • -std=c99 -pedantic 编译良好。
      • -std=c89 -pedantic 给出警告。 “警告:初始化元素在加载时不可计算[默认启用]”。

      (我不确定这个案例的标准之间的区别,所以我不想推测它为什么在 C99 而不是 C89 中有效。可能与 VLA 有关?)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-04
        • 1970-01-01
        • 2015-07-21
        • 1970-01-01
        • 2020-06-29
        • 2012-03-22
        相关资源
        最近更新 更多