¿Por qué recibo una advertencia del compilador con "int __attribute __ ((address (0x3000))) x;”

2

Estoy tratando de entender por qué recibo la siguiente advertencia

#include <xc.h>

int main (void)
{
     int __attribute__((address(0x3000))) x;


     while(1);

     return 0;
 }
  

PIC24_Attributes.c: 13: 5: advertencia: ignorando el atributo de dirección aplicado a x automática

Sé que __attribute__address((address(0x3000))) x significa almacenar la variable de tipo int x en la dirección del ESPACIO DE DATOS 0x3000

Cuando descargo el programa y lo depuro, veo que la dirección de x es 0x856

pero cuando lo coloco globalmente, la advertencia desaparece, y cuando depuro, la dirección de x es 0x3000.

Busqué en Google la advertencia que recibí y encontré a alguien con la misma advertencia que yo, pero con el atributo de espacio ( enlace )

Por lo que entendí, __attribute__ solo funciona para variables estáticas, y las variables automáticas (no sé por qué es automática, es un int) se asignan de forma dinámica.

Alguien puede explicarlo, por favor, ya que entiendo que ' atributo ((dirección (...))) significa almacenar la siguiente variable en una dirección determinada.

  • Microncotroller: PIC24FJ1024GB610 (Microchip)
  • Depurador: PKOB (placa de desarrollo de Explorer 16/32)
pregunta Forat

3 respuestas

4

Automático se refiere al concepto C de duración del almacenamiento automático . En C, hay principalmente 2 duraciones de almacenamiento diferentes para los objetos: static (no debe confundirse con la palabra clave static , que es un especificador de clase de almacenamiento ) y automático . Un objeto conservará su último valor almacenado y se almacenará en una dirección constante durante toda su vida útil.

La duración del almacenamiento estático significa "la duración de todo el programa" , es decir, desde antes de ingresar main la primera vez hasta después de salir de él.

La duración del almacenamiento automático es para los objetos "declarados sin vínculo y sin el especificador de clase de almacenamiento static ": el sin vínculo significa que no se declaran globalmente, se declaran / definido dentro de un bloque y no declarado con el especificador de clase de almacenamiento extern . Su vida es principalmente hasta el final del bloque.

Ahora en tu programa,

#include <xc.h>
int main (void)
{
     int __attribute__((address(0x3000))) x;
     while(1);
     return 0;
}

Dado que la definición-definición int x; no tiene ni el extern ni el static especificador de la clase de almacenamiento , define un objeto int de automático duración de almacenamiento dentro de la función main . Cada vez que se ingresa la función main , se debe asignar un objeto distinto nuevo . C permite que la función main se llame a sí misma recursivamente, así que claramente x simplemente no puede estar en una dirección fija aquí. De hecho, en muchas arquitecturas informáticas, x puede que ni siquiera resida en la memoria, puede estar en un registro u optimizarse por completo.

Solo tiene sentido tener un objeto que tenga una duración de almacenamiento static , a diferencia de la duración del almacenamiento automático, para ubicarse en una dirección fija. Además de declarar esto en el archivo ámbito:

int __attribute__((address(0x3000))) x;
int main(void) { ... }

que haría que x sea accesible en todas partes dentro del archivo, también puede hacer que el identificador sea privado a la función main , pero aún así conservar la duración del almacenamiento estático , usando el static especificador de clase de almacenamiento :

int main(void) { 
    static int __attribute__((address(0x3000))) x;
    ... 
}

Ahora, el identificador x no es visible fuera de la función main ; y solo se define exactamente un x , y su duración de almacenamiento es estática, lo que significa que es para toda la duración del programa, ya que su duración de almacenamiento no es automática , pero tendrá un Dirección fija para todo el tiempo de ejecución del programa, se le puede pedir al compilador que la ubique en una dirección alternativa.

    
respondido por el Antti Haapala
10

x es una variable local. Ni siquiera necesariamente tiene una dirección de almacenamiento. Por lo tanto, no necesariamente puede asignarle una dirección.

Haz x global.

"automático" es el tipo de almacenamiento de una variable, no el tipo de datos, por lo que ser int es ortogonal a ser static o automatic .

Es un poco sorprendente que tu depurador vea una dirección para main -local x en absoluto. Sería totalmente apropiado para el compilador ver que x , analizar dónde se usa, ver que no se usa , y simplemente no asigne ninguna ubicación en absoluto.

Por ejemplo:

test_temp_storage.c

/* test_temp_storage.c */
int main()
{
  int x;
  while(1);
  return 0;
}

construyendo, con -Os , algo que cualquier persona sensata haría con un compilador orientado a microcontroladores (optimizando para el tamaño del código):

$> clang -g -Os -o test test_temp_storage.c

depurando, rompe antes de entrar al bucle while:

$> gdb test
(gdb) break test_temp_storage.c 
Breakpoint 1 at 0x400490: file test_temp_storage.c, line 5.
(gdb) run
Starting program: /home/marcus/src/scratch/test 

Breakpoint 1, main () at test_temp_storage.c:5
5     while(1);
(gdb) print x
$1 = <optimized out>
(gdb) print &x
Can't take address of "x" which isn't an lvalue.

Como puede ver, no existe x aquí.

    
respondido por el Marcus Müller
6

Para entender por qué no puede asignar la dirección de una variable local "automática", considere la posibilidad de recursión.

int treesum(const tree *x)
{
    int sum = x->value;
    if (x->left)
        sum += treesum(x->left);
    if (x->right)
        sum += treesum(x->right);
    return sum;
}

Cada invocación recursiva de treesum debe tener su copia propia de la variable sum . Por lo tanto, a todos no se les puede asignar la misma dirección.

La regla se aplica a todas variables automáticas, no solo a las variables automáticas en las funciones llamadas recursivamente, porque el compilador no siempre sabe si una función se llamará recursivamente; puede ser que f llame g llame h llame f, y h esté definido en otro archivo fuente.

    
respondido por el zwol

Lea otras preguntas en las etiquetas