ошибка: элемент инициализатора не является константой - PullRequest
1 голос
/ 27 марта 2012
#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 ')

Теперь мой вопрос: есть ли любойОбходной путь для меня без перемещения выражения внутри функции.Я не могу двигаться, так как эти структуры используются во многих местах моего кода.

Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

Ответы [ 3 ]

1 голос
/ 27 марта 2012

Уродливый путь:

#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
 *
 * */
0 голосов
/ 27 марта 2012
typedef struct {
    int x;
    int y;
    int z;
    FIRST_T *p;
} SECOND_T;

Когда вы объявляете переменную этой структуры const, все ее члены становятся const, так как они сохраняются в ПЗУ. int const x;, int const y; и т. Д. Для указателя это означает, что он поворачивается FIRST_T * const p;. То есть постоянный указатель на непостоянные данные. Указанный тип все еще не 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 выдает предупреждения. msgstr "предупреждение: элемент инициализатора не вычисляется во время загрузки [включен по умолчанию]".

(Я не уверен в разнице между стандартами для этого случая, поэтому я бы предпочел не рассуждать, почему он работает в C99, а не в C89. Может быть, это связано с VLA?)

0 голосов
/ 27 марта 2012

как насчет

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}};

, а затем просто измените #define s, чтобы синхронизировать 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

.

...