
tomlogic
Recibo un error en la línea 6 (inicializar my_foo a foo_init) del siguiente programa y no estoy seguro de entender por qué.
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;
}
Tenga en cuenta que esta es una versión simplificada de un proyecto más grande de varios archivos en el que estoy trabajando. El objetivo era tener una sola constante en el archivo de objeto, que varios archivos pudieran usar para inicializar una estructura de estado. Dado que es un destino incrustado con recursos limitados y la estructura no es tan pequeña, no quiero varias copias de la fuente. Prefiero no usar:
#define foo_init { 1, 2, 3 }
También estoy tratando de escribir código portátil, así que necesito una solución que sea C89 o C99 válida.
¿Tiene esto que ver con los ORG en un archivo de objeto? ¿Que las variables inicializadas van a un ORG y se inicializan copiando el contenido de un segundo ORG?
Tal vez solo necesite cambiar mi táctica y hacer que una función de inicialización haga todas las copias al inicio. ¿A menos que haya otras ideas por ahí?

Hormiga
En lenguaje C, los objetos con duración de almacenamiento estático deben inicializarse con expresiones constanteso con inicializadores agregados que contienen expresiones constantes.
Un objeto “grande” nunca es una expresión constante en C, incluso si el objeto se declara como const
.
Además, en lenguaje C, el término “constante” se refiere a constantes literales (me gusta 1
, 'a'
, 0xFF
etcétera), miembros de la enumeración y resultados de operadores tales como sizeof
. Los objetos calificados const (de cualquier tipo) son no constantes en la terminología del lenguaje C. No se pueden utilizar en inicializadores de objetos con duración de almacenamiento estático, independientemente de su tipo.
Por ejemplo, esto es NO una constante
const int N = 5; /* `N` is not a constant in C */
Lo anterior N
sería una constante en C++, pero no es una constante en C. Entonces, si intentas hacer
static int j = N; /* ERROR */
obtendrá el mismo error: un intento de inicializar un objeto estático con una no constante.
Esta es la razón por la cual, en lenguaje C, usamos predominantemente #define
para declarar constantes con nombre, y también recurrir a #define
para crear inicializadores agregados con nombre.

Samuel Klatchko
Es una limitación del lenguaje. En la sección 6.7.8/4:
Todas las expresiones en un inicializador para un objeto que tiene una duración de almacenamiento estática serán expresiones constantes o literales de cadena.
En la sección 6.6, la especificación define lo que debe considerarse una expresión constante. En ningún lugar dice que una variable const debe considerarse una expresión constante. Es legal que un compilador amplíe esto (6.6/10 - An implementation may accept other forms of constant expressions
) pero eso limitaría la portabilidad.
si puedes cambiar my_foo
por lo que no tiene almacenamiento estático, estaría bien:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: Para quien llega a este puesto por arm-none-eabi-gcc.exe
error de compilación en MCU STM32:
Cambie su cadena de herramientas a gnu-tools-for-stm32.9-2020-q2-update
.
A partir de GCC V8.1+, se admite el inicializador constante anidado y se compilará el siguiente código.
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.exe
en gnu-tools-for-stm32.7-2018-q2-update
está basado en gcc v7.3.1
¡y el código anterior no se compilará! Pero gnu-tools-for-stm32.9-2020-q2-update
usos gcc v9.3.1
y compilará.
Para obtener más información, consulte estos:
¿Por qué el “elemento inicializador no es una constante”… ya no funciona?
y
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18

achora
Solo como ilustración por comparación y contraste El código es de http://www.geeksforgeeks.org/g-fact-80/
/El código falla en gcc y pasa en 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;
}
Esto es un poco viejo, pero me encontré con un problema similar. Puedes hacer esto si usas un puntero:
#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;
}
gcc 7.4.0 no puede compilar códigos de la siguiente manera:
#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: error: el elemento inicializador no es constante const char * str2 = str1;
De hecho, una cadena “const char *” no es una constante de tiempo de compilación, por lo que no puede ser un inicializador. Pero una cadena “const char * const” es una constante de tiempo de compilación, debería poder ser un inicializador. Creo que este es un pequeño inconveniente de CLang.
El nombre de una función es, por supuesto, una constante de tiempo de compilación. Así que este código funciona:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
Tuve este error en el código que se veía así:
int A = 1;
int B = A;
La solución es cambiarlo a esto.
int A = 1;
#define B A
El compilador asigna una ubicación en la memoria a una variable. El segundo es intentar asignar una segunda variable a la misma ubicación que la primera, lo que no tiene sentido. El uso del preprocesador de macros resuelve el problema.
Solucionado en gcc-8.1 y versiones posteriores, consulte la respuesta de @Zaman a continuación para obtener más detalles.
– bruce
1 oct 2021 a las 8:07