Fout initializer-element is niet constant bij het initialiseren van variabele met const

Ik krijg een foutmelding op regel 6 (initialiseer my_foo naar foo_init) van het volgende programma en ik weet niet zeker of ik begrijp waarom.

typedef struct foo_t {
    int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
    return 0;
}

Houd er rekening mee dat dit een vereenvoudigde versie is van een groter project met meerdere bestanden waaraan ik werk. Het doel was om één constante in het objectbestand te hebben, die meerdere bestanden konden gebruiken om een ​​statusstructuur te initialiseren. Omdat het een ingebed doel is met beperkte middelen en de structuur niet zo klein is, wil ik niet meerdere kopieën van de bron. Ik gebruik liever niet:

#define foo_init { 1, 2, 3 }

Ik probeer ook draagbare code te schrijven, dus ik heb een oplossing nodig die geldig is C89 of C99.

Heeft dit te maken met de ORG’s in een objectbestand? Die geïnitialiseerde variabelen gaan in één ORG en worden geïnitialiseerd door de inhoud van een tweede ORG te kopiëren?

Misschien moet ik gewoon mijn tactiek veranderen en een initialisatiefunctie hebben om alle kopieën bij het opstarten te maken. Tenzij er andere ideeën zijn?


Antwoord 1, autoriteit 100%

In C-taal moeten objecten met een statische opslagduur worden geïnitialiseerd met constante expressiesof met geaggregeerde initializers die constante expressies bevatten.

Een “groot” object is nooit een constante expressie in C, zelfs niet als het object wordt gedeclareerd als const.

Bovendien verwijst de term “constant” in C-taal naar letterlijke constanten(zoals 1, 'a', 0xFFenzovoort), enum-leden en resultaten van operators zoals sizeof. Const-gekwalificeerde objecten (van elk type) zijn geen constantenin C-taalterminologie. Ze kunnen niet worden gebruikt in initializers van objecten met een statische opslagduur, ongeacht hun type.

Dit is bijvoorbeeld NIETeen constante

const int N = 5; /* `N` is not a constant in C */

De bovenstaande Nzou een constante zijn in C++, maar het is geen constante in C. Dus, als je probeert

static int j = N; /* ERROR */

u krijgt dezelfde foutmelding: een poging om een ​​statisch object te initialiseren met een niet-constante.

Dit is de reden waarom we in C-taal voornamelijk #definegebruiken om benoemde constanten te declareren, en ook onze toevlucht nemen tot #defineom benoemde verzamelinitialisaties te maken.


Antwoord 2, autoriteit 27%

Het is een beperking van de taal. In sectie 6.7.8/4:

Alle expressies in een initialisatie voor een object met een statische opslagduur moeten constante expressies of letterlijke tekenreeksen zijn.

In paragraaf 6.6 definieert de specificatie wat als een constante uitdrukking moet worden beschouwd. Nergens staat dat een const-variabele als een constante expressie moet worden beschouwd. Het is legaal voor een compiler om dit uit te breiden (6.6/10 - An implementation may accept other forms of constant expressions), maar dat zou de portabiliteit beperken.

Als je my_fookunt wijzigen zodat het geen statische opslag heeft, zou het goed zijn:

int main()
{
    foo_t my_foo = foo_init;
    return 0;
}

Antwoord 3, autoriteit 2%

Ter illustratie door te vergelijken en te contrasteren
De code is van http://www.geeksforgeeks.org/g-fact-80/
/De code mislukt in gcc en slaagt in g++/

#include<stdio.h>
int initializer(void)
{
    return 50;
}
int main()
{
    int j;
    for (j=0;j<10;j++)
    {
        static int i = initializer();
        /*The variable i is only initialized to one*/
        printf(" value of i = %d ", i);
        i++;
    }
    return 0;
}

Antwoord 4

2021: voor wie dit bericht bereikt vanwege arm-none-eabi-gcc.execompileerfout op STM32 MCU’s:
Verander uw toolchain in gnu-tools-for-stm32.9-2020-q2-update.

Vanaf GCC V8.1+ wordt geneste constante initialisatie ondersteund en de onderstaande code wordt gecompileerd.

const int a = 1;
const int b = a +1;
typedef struct foo_t {
    int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
    return 0;
}

arm-none-eabi-gcc.exein gnu-tools-for-stm32.7-2018-q2-updateis gebaseerd op gcc v7.3.1en de bovenstaande code zal niet compileren! Maar gnu-tools-for-stm32.9-2020-q2-updategebruikt gcc v9.3.1en zal compileren.

Zie deze voor meer informatie:
Waarom “initializer-element geen constante is” is … werkt het niet meer?
en
https://gcc.gnu.org/bugzilla/show_bug.cgi? id=69960#c18


Antwoord 5

Dit is een beetje oud, maar ik kwam een ​​soortgelijk probleem tegen. U kunt dit doen als u een aanwijzer gebruikt:

#include <stdio.h>
typedef struct foo_t  {
    int a; int b; int c;
} foo_t;
static const foo_t s_FooInit = { .a=1, .b=2, .c=3 };
// or a pointer
static const foo_t *const s_pFooInit = (&(const foo_t){ .a=2, .b=4, .c=6 });
int main (int argc, char **argv) {
    const foo_t *const f1 = &s_FooInit;
    const foo_t *const f2 = s_pFooInit;
    printf("Foo1 = %d, %d, %d\n", f1->a, f1->b, f1->c);
    printf("Foo2 = %d, %d, %d\n", f2->a, f2->b, f2->c);
    return 0;
}

Antwoord 6

gcc 7.4.0 kan geen codes compileren zoals hieronder:

#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
    printf("%s - %s\n", str1, str2);
    return 0;
}

constchar.c:3:21: fout: initialisatie-element is niet constant
const char * str2 = str1;

In feite is een “const char *”-tekenreeks geen constante tijdens het compileren, dus het kan geen initialisatie zijn. Maar een “const char * const” string is een constante tijdens het compileren, het zou een initialisatie moeten kunnen zijn. Ik vind dit een klein nadeel van CLang.

Een functienaam is natuurlijk een constante tijdens het compileren. Dus deze code werkt:

void func(void)
{
    printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
    f();
    return 0;
}

Antwoord 7

Ik had deze fout in code die er als volgt uitzag:

int A = 1;
int B = A;

De oplossing is om het hierin te veranderen

int A = 1;
#define B A

De compiler wijst een locatie in het geheugen toe aan een variabele. De tweede probeert een tweede variabele toe te wijzen aan dezelfde locatie als de eerste – wat geen zin heeft. Het gebruik van de macro-preprocessor lost het probleem op.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes