¿Qué es exactamente __attribute__ en la programación integrada?

¿Qué es exactamente el atributo en la programación integrada?

Creo que los veteranos que leen código incrustado a menudo ven algunas definiciones de tipos, variables y funciones que tienen identificadores de atributos . ¿Qué hace exactamente este identificador? ¿Cuáles son los usos? Hablemos de eso hoy.

El atributo puede especificar detalles en tiempo de compilación . Puede actuar sobre variables, funciones, estructuras y miembros de estructuras.
Vale la pena señalar que el mecanismo de Atributos no es parte del estándar C. Por lo tanto, los programas que usan atributos a veces no son portátiles entre compiladores. Sin embargo, la cadena de herramientas de compilación utilizada por la mayoría de los IDE de C/C++ en el mercado es GCC, y la cadena de herramientas de compilación de muchos IDE comerciales también se basa en la versión optimizada de GCC. Por lo tanto, el __atributo__ de GNU C es generalmente compatible, y este mecanismo de __atributo__ se usa a menudo en el código fuente de Uboot y Linux.

formato de atributo

__attribute__ ((attribute-list)) 

ejemplo:

extern void  die(const char *format,...)    __attribute__( (noreturn) );  // 只含一个属性 noreturn

extern void  die(const char *format,...)    __attribute__( (noreturn,  format(printf, 1, 2)) ); // 含两个属性:noreturn,  format(printf, 1, 2);两个属性以逗号分隔

Algunos atributos de atributos comunes

atributo ((obsoleto))

Ejemplo: para la administración de versiones, declare que la función se descartará y se emitirá un aviso en el momento de la compilación para recordar a los desarrolladores que usen la última versión de la función o variable.

int spi_cal_clock(int fapb, int hz, int duty_cycle, uint32_t* reg_o) __attribute__((deprecated));

Al compilar, se le pedirá: atributo_deprecated.c:33: advertencia: 'spi_cal_clock()' está en desuso.

atributo ((always_inline)) 与attribute ((noinline))

En la explicación detallada de las funciones en línea (inline functions) , presentamos la diferencia entre funciones en línea y funciones no en línea. Tanto el atributo ((always_inline)) como el atributo ((noinline)) actúan sobre el compilador, tratando de forzar que la función correspondiente esté en línea o no en línea durante la fase de compilación.
Ejemplo:

__attribute__((always_inline)) inline int32_t add(int32_t x, int32_t y) {

​	return (x+y);

}

La función anterior tiene dos líneas. El compilador puede ignorar lo siguiente en línea (por ejemplo, c89 no admite esta palabra clave, pero C99 admite esta palabra clave). Pero el atributo anterior ((always_inline)) (el atributo admitido por el compilador GCC) no se ignorará; de lo contrario, se informará de un error.

atributo ((sin retorno))

Permite que una función no se ejecute hasta una declaración de retorno.

static void __ubsan_default_handler(struct source_location *loc, const char *func)
{
    char msg[60] = {};
    (void) strlcat(msg, "Undefined behavior of type ", sizeof(msg));
    (void) strlcat(msg, func + strlen("__ubsan_handle_"), sizeof(msg));
    esp_system_abort(msg);
}

La compilación de la declaración anterior directamente puede desencadenar una advertencia: esta función puede regresar con o sin un valor.
La siguiente declaración debe usarse para indicar que la función no regresa eventualmente, porque la excepción de cancelación se activa directamente y el dispositivo se reiniciará, por lo que no es necesario regresar.

static void __ubsan_default_handler(struct source_location *loc, const char *func) __attribute__((noreturn));

atributo ((sobrecargable))

Las declaraciones admiten la sobrecarga. Para las funciones del lenguaje C, puede definir varias funciones con el mismo nombre pero con diferentes parámetros pasados. Al llamar, el compilador seleccionará automáticamente el prototipo de función de acuerdo con los parámetros.

__attribute__((overloadable)) void print(NSString *string)

__attribute__((overloadable)) void print(Int *int)

atributo ((alias()))

Se utiliza para establecer alias de función.

int __centon() 
{
  printf("in %s\n",__FUNCTION__);
  return 0;
}

void centon() __attribute__((alias("__centon")));//设置函数别名,原函数是__cencon, 别名是centon. 后面可以使用 centon 代替 __centon.

atributo ((no nulo()));

El parámetro especificado utilizado para declarar una función no puede ser nulo

extern void *
my_memcpy (void *dest, const void *src, size_t len)
        __attribute__((nonnull (1, 2))); // 参数 dest、src 不能为 null,否则编译器会发出警告

atributo ((constructor(PRIORIDAD))) 与atributo ((destructor(PRIORIDAD)))

Atributos de constructores y destructores, con prioridad (PRIORITY). Puede actuar sobre funciones y objetos de variables globales (o variables estáticas), aquí tomamos funciones como ejemplo.
Las funciones con el atributo "construcción" se ejecutarán antes que la función main(), mientras que las funciones declaradas con el atributo "destructor" se ejecutarán cuando finalice main(). Se utiliza principalmente para realizar muchas acciones de preprocesamiento o acciones de posprocesamiento antes y después de la ejecución de la función main().

void main_enter1() __attribute__((constructor(99)));//main_enter函数在进入main函数前调用
void main_enter2() __attribute__((constructor(100)));//main_enter函数在进入main函数前调用
void main_exit() __attribute__((destructor));//main_exit函数在main函数返回后调用

La función anterior, antes de ingresar a main(), llama a main_enter1() porque su prioridad es 99 y luego llama a main_enter2() porque su prioridad es 100. Finalmente, después de que se ejecute main(), se llamará a main_exit().

Atributo de atributo de alineación ((alineado(x))) y __attribute__((empaquetado))

Los atributos de alineación se pueden utilizar para especificar la alineación de la memoria. El valor de alineación debe ser una potencia entera de 2.
Por ejemplo, int8_t foo; se puede almacenar en cualquier lugar en 0x100\0x101\0x102\0x103. Pero pase el atributo
int8_t foo ((aligned(4))); para especificar su alineación como 4 bytes. Entonces su alineación se convierte en 0x100\0x104\0x108. Por ejemplo, calcule las longitudes de los siguientes cuatro tipos de variables:

typedef struct {
    
    
    int8_t var1;
    int32_t var2;
    int8_t var3;
} custom_type1;

typedef struct {
    
    
    int8_t var1 __attribute__((aligned(4)));
    int8_t var2 __attribute__((aligned(4)));
    int8_t var3 __attribute__((aligned(4)));
}custom_type2;

typedef struct {
    
    
    int8_t var1;
    int32_t var2;
    int8_t var3;
}custom_type3 __attribute__((aligned)); // 自动按字对齐,如果aligned 后面不紧跟一个指定的数字值,那么编译器将依据你的目标机器情况使用最大最有益的对齐方式。ligned 属性使被设置的对象占用更多的空间,相反的,使用packed 可以减小对象占用的空间。需要注意的是,attribute 属性的效力与你的连接器也有关,如果你的连接器最大只支持16 字节对齐,那么你此时定义32 字节对齐也是无济于事的。ligned 属性使被设置的对象占用更多的空间,相反的,使用packed 可以减小对象占用的空间。

typedef struct {
    
    
    int8_t var1;
    int32_t var2;
    int8_t var3;
} custom_type4 __attribute__((packed)); // 不自动对齐。此时 sizeof( custom_type4) 应该是 6bytes. 使用该属性可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐。使用该属性对struct或者union类型进行定义,设定其类型的每一个变量的内存约束。当用在enum类型定义时,暗示了应该使用最小完整的类型。告诉(不是强制)编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法。

Explore el tamaño de la estructura final bajo diferentes alineaciones. La respuesta está al final del texto.

atributo ((sección (xx)))

sección controla el nombre de la sección de la variable o función en tiempo de compilación. Es ampliamente utilizado en el desarrollo de software embebido.Por ejemplo, cuando hay un Flash o RAM externo, las variables o funciones deben colocarse en el espacio de almacenamiento externo, que se puede operar especificando el nombre del segmento en el script de enlace. Al programar una MCU usando MPU (protección de memoria), es necesario dividir la memoria en áreas y colocar variables o códigos en las áreas correspondientes, generalmente a través de operaciones de segmento.

Cuando se trata de sección, tenemos que hablar del área básica donde se almacena el código. Después de que el compilador compila, el código se divide en diferentes secciones, la sección RO (ReadOnly) almacena secciones de código y constantes, la sección RW (ReadWrite) almacena variables estáticas legibles y escribibles y variables globales, la sección ZI (ZeroInit) almacena en Variables en el RW segmento inicializado a 0.
atributo ((sección("nombre_sección"))), su función es poner la función o los datos de la función en la sección correspondiente al nombre especificado "nombre_sección".

const int identifier[3] __attribute__ ((section ("ident"))) = { 1,2,3 };

void myfunction (void) __attribute__ ((section ("ext_function")))

Después de compilar el código anterior, los segmentos donde se encuentran la matriz y la función son respectivamente "sangría" y "ext_function" en lugar del segmento de texto normal.

atributo ((sin usar)) 与atributo ((usado))

En un programa C, si se define una función estática\variable a pero no se utiliza, habrá una advertencia al compilar: 'a' definida pero no utilizada [-Wunused-function].

uint16_t acl_length __attribute__((unused));

__attribute__((unused)) static uint32_t get_cause(void)
{
    uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, \
                                            RTC_CNTL_WAKEUP_CAUSE);
    return wakeup_cause;
}

Significa que es probable que la función o variable no se use. En este momento, el compilador no generará advertencias para esta función de acuerdo con __attribute__((unused)).
También se puede declarar en parámetros que no se utilizan en la implementación de la función, por ejemplo:

int main(int argc __attribute__((unused)), char **argv)

La función del atributo ((used)) es decirle al compilador que el símbolo que declaré debe reservarse. Después de ser modificado por used, significa que aunque no se haga referencia a la función, no se optimizará al compilar y vincular. Sin esta decoración, el enlazador puede eliminar secciones sin referencia.

atributo ((débil))

Si dos o más símbolos globales tienen el mismo nombre, y uno de ellos se declara como símbolo débil (débil símbolo), y el otro no agrega un modificador débil, estos símbolos globales con el mismo nombre no causarán un error de redefinición. Cuando existe un objeto sin un modificador débil, el enlazador ignorará el modificado por un símbolo débil, si no hay ningún objeto agregado con un modificador débil, se utilizará el objeto modificado con un símbolo débil. Aquellos que estén
interesados ​​pueden consultar mi blog mencionado anteriormente: Explicación detallada de símbolos débiles y referencias débiles en lenguaje C.

atributo ((const))

Este atributo solo se puede usar en funciones con parámetros de tipo numérico. Cuando la función con parámetros numéricos se llama repetidamente, dado que el valor de retorno es el mismo, el compilador puede optimizar el procesamiento en este momento. Excepto por la primera operación, las otras solo necesitan devolver el primer resultado y luego pueden mejorar la eficiencia. Este atributo es principalmente adecuado para algunas funciones sin estado estático (estado estático) y efectos secundarios, y el valor devuelto solo depende de los parámetros de entrada.

__attribute__((const)) int f() {
    return 1;
}

Para obtener más atributos de __attribute__, consulte el manual de GCC. Cuando necesitemos usar algunas características avanzadas del compilador, podemos encontrarlas en el manual.

Resumir

  1. __attribute__ es un atributo de compilación, que se utiliza para describir un indicador de compilación especial para el compilador, que se puede utilizar para la comprobación de errores o la optimización avanzada al compilar el programa. Es una de las características de GNU C y se usa en muchos lugares del sistema.
  2. Los ingenieros senior de desarrollo integrado deben aumentar su comprensión de las opciones de optimización del compilador, como el mecanismo de atributos , que puede lograr un uso más avanzado y escribir programas más seguros y confiables.

La respuesta a la propiedad de alineación.

custom_type1 len = 12 // 编译器按照默认自动对齐
custom_type2 len = 12 // 每个成员都 4bytes 对齐
custom_type3 len = 12 // 32 位编译器默认 4bytes 对齐
custom_type4 len = 12 // 因为我的编译器禁止这种 packed 优化,因此最终会在编译时提出警告,但仍以最优长度进行对齐

(Gracias por los favoritos y me gusta, su apoyo es la fuerza impulsora de mi creación continua)

Supongo que te gusta

Origin blog.csdn.net/wangyx1234/article/details/129843262
Recomendado
Clasificación