trigger ejemplo autonomous_transaction c c-preprocessor

ejemplo - pragma autonomous_transaction trigger



Efecto paquete#pragma (11)

Me preguntaba si alguien podría explicarme qué hace la declaración del preprocesador del #pragma pack y, lo que es más importante, por qué uno querría usarla.

Revisé la página de MSDN , que me brindó algunas ideas, pero esperaba escuchar más de personas con experiencia. Lo he visto en el código antes, aunque parece que ya no puedo encontrarlo.


  1. # pragma pack (n) simplemente establece la nueva alineación.
  2. # pragma pack () establece la alineación con la que estaba en vigor cuando se inició la compilación.
  3. # pragma pack (push [, n]) empuja la configuración de alineación actual en una pila interna y luego establece opcionalmente la nueva alineación.
  4. # pragma pack (pop) restaura la configuración de alineación a la guardada en la parte superior de la pila interna (y elimina esa entrada de la pila). Tenga en cuenta que #pragma pack ([n]) no influye en esta pila interna; por lo tanto, es posible tener #pragma pack (push) seguido de múltiples #pragma pack (n) instancias y finalizado por un solo paquete #pragma (pop).

Ejemplos:

#pragma pack(push, 1) // exact fit - no padding struct MyStruct { char b; int a; int array[2]; }; #pragma pack(pop) //back to whatever the previous packing mode was Or #pragma pack(1) // exact fit - no padding struct MyStruct { char b; int a; int array[2]; }; #pragma pack() //back to whatever the previous packing mode was Or #pragma pack(1) // exact fit - no padding struct MyStruct { char b; int a; int array[2]; };


El compilador podría alinear miembros en estructuras para lograr el máximo rendimiento en la plataforma determinada. #pragma pack directiva #pragma pack permite controlar esa alineación. Por lo general, debe dejarlo de manera predeterminada para un rendimiento óptimo. Si necesita pasar una estructura a la máquina remota, generalmente usará #pragma pack 1 para excluir cualquier alineamiento no deseado.


He visto a gente usarlo para asegurarse de que una estructura toma una línea de caché completa para evitar compartir falsamente en un contexto multiproceso. Si va a tener una gran cantidad de objetos que van a estar vagamente empaquetados de manera predeterminada, podría ahorrar memoria y mejorar el rendimiento de la memoria caché para empaquetarlos, aunque el acceso a la memoria no alineada ralentizará las cosas, por lo que podría ser un inconveniente.


Le dice al compilador el límite para alinear objetos en una estructura. Por ejemplo, si tengo algo como:

struct foo { char a; int b; };

Con una máquina típica de 32 bits, normalmente "querrás" tener 3 bytes de relleno entre a y b para que b aterrice en un límite de 4 bytes para maximizar su velocidad de acceso (y eso es lo que típicamente sucederá de manera predeterminada )

Sin embargo, si tiene que coincidir con una estructura definida externamente, quiere asegurarse de que el compilador establece su estructura exactamente de acuerdo con esa definición externa. En este caso, puede darle al compilador un #pragma pack(1) para indicarle que no inserte ningún relleno entre los miembros. Si la definición de la estructura incluye relleno entre los miembros, debe insertarlo explícitamente (por ejemplo, típicamente con miembros nombrados unusedN o ignoreN , o algo en ese orden).


Lo he usado en el código anteriormente, aunque solo para interactuar con el código heredado. Esta era una aplicación Mac OS X Cocoa que necesitaba cargar archivos de preferencias de una versión anterior de Carbon (que era compatible con la versión original de M68k System 6.5 ... se entiende). Los archivos de preferencias en la versión original eran un volcado binario de una estructura de configuración, que usaba el #pragma pack(1) para evitar ocupar espacio extra y guardar basura (es decir, los bytes de relleno que de otro modo estarían en la estructura).

Los autores originales del código también habían usado #pragma pack(1) para almacenar las estructuras que se utilizaron como mensajes en la comunicación entre procesos. Creo que la razón aquí fue para evitar la posibilidad de tamaños de relleno desconocidos o modificados, ya que el código a veces miraba una parte específica de la estructura del mensaje al contar una cantidad de bytes desde el inicio (ewww).


Los elementos de datos (por ejemplo, miembros de clases y estructuras) se alinean normalmente en los límites WORD o DWORD para los procesadores de generación actuales a fin de mejorar los tiempos de acceso. Recuperar un DWORD en una dirección que no es divisible por 4 requiere al menos un ciclo de CPU adicional en un procesador de 32 bits. Entonces, si tiene, por ejemplo, tres miembros char a, b, c; , en realidad tienden a tomar 6 o 12 bytes de almacenamiento.

#pragma permite anular esto para lograr un uso del espacio más eficiente, a expensas de la velocidad de acceso, o para la coherencia de los datos almacenados entre diferentes objetivos del compilador. Me divertí mucho con esta transición del código de 16 bits a 32 bits; Espero que portar código de 64 bits cause los mismos tipos de dolores de cabeza a algún código.


Probablemente solo desee utilizar esto si estuviera codificando a algún hardware (por ejemplo, un dispositivo mapeado en la memoria) que tuviera requisitos estrictos para ordenar y alinear el registro.

Sin embargo, esto parece una herramienta bastante contundente para lograr ese fin. Un mejor enfoque sería codificar un mini-controlador en ensamblador y darle una interfaz de llamada C en lugar de buscar con este pragma.


Tenga en cuenta que hay otras formas de lograr la coherencia de los datos que ofrece #pragma pack (por ejemplo, algunas personas usan #pragma pack (1) para las estructuras que deben enviarse a través de la red). Por ejemplo, vea el siguiente código y su resultado posterior:

#include <stdio.h> struct a { char one; char two[2]; char eight[8]; char four[4]; }; struct b { char one; short two; long int eight; int four; }; int main(int argc, char** argv) { struct a twoa[2] = {}; struct b twob[2] = {}; printf("sizeof(struct a): %i, sizeof(struct b): %i/n", sizeof(struct a), sizeof(struct b)); printf("sizeof(twoa): %i, sizeof(twob): %i/n", sizeof(twoa), sizeof(twob)); }

El resultado es el siguiente: sizeof (struct a): 15, sizeof (struct b): 24 sizeof (twoa): 30, sizeof (twob): 48

Observe cómo el tamaño de la estructura a es exactamente lo que es el conteo de bytes, pero la estructura b tiene un relleno agregado (vea this para detalles sobre el relleno). Al hacer esto en comparación con el paquete #pragma, puede tener el control de convertir el "formato de conexión" en los tipos apropiados. Por ejemplo, "char two [2]" en un "short int", etcétera.


Un compilador puede colocar miembros de la estructura en límites de bytes particulares por razones de rendimiento en una arquitectura particular. Esto puede dejar relleno sin usar entre los miembros. El empaque de estructura obliga a los miembros a ser contiguos.

Esto puede ser importante, por ejemplo, si necesita una estructura para ajustarse a un archivo o formato de comunicación en particular, donde los datos necesitan que los datos estén en posiciones específicas dentro de una secuencia. Sin embargo, dicho uso no se ocupa de problemas de endianidad, por lo tanto, aunque se use, puede que no sea portátil.

También puede superponerse exactamente a la estructura de registro interno de algún dispositivo de E / S, como un controlador UART o USB, por ejemplo, para que el acceso de registro sea a través de una estructura en lugar de direcciones directas.


#pragma pack instruye al compilador para empacar miembros de la estructura con una alineación particular. La mayoría de los compiladores, al declarar una estructura, insertarán relleno entre los miembros para asegurarse de que estén alineados con las direcciones apropiadas en la memoria (generalmente un múltiplo del tamaño del tipo). Esto evita la penalización del rendimiento (o error absoluto) en algunas arquitecturas asociadas con el acceso a variables que no están alineadas correctamente. Por ejemplo, dados enteros de 4 bytes y la siguiente estructura:

struct Test { char AA; int BB; char CC; };

El compilador podría elegir colocar la estructura en la memoria así:

| 1 | 2 | 3 | 4 | | AA(1) | pad.................. | | BB(1) | BB(2) | BB(3) | BB(4) | | CC(1) | pad.................. |

y sizeof(Test) sería 4 × 3 = 12, aunque solo contenga 6 bytes de datos. El caso de uso más común para #pragma (que yo sepa) es cuando se trabaja con dispositivos de hardware donde se necesita asegurar que el compilador no inserte el relleno en los datos y que cada miembro siga el anterior. Con #pragma pack(1) , la estructura anterior se establecería así:

| 1 | | AA(1) | | BB(1) | | BB(2) | | BB(3) | | BB(4) | | CC(1) |

Y sizeof(Test) sería 1 × 6 = 6.

Con #pragma pack(2) , la estructura anterior se distribuiría así:

| 1 | 2 | | AA(1) | pad.. | | BB(1) | BB(2) | | BB(3) | BB(4) | | CC(1) | pad.. |

Y sizeof(Test) sería 2 × 4 = 8.


#pragma se usa para enviar mensajes no portátiles (como en este compilador solamente) al compilador. Cosas como la desactivación de ciertas advertencias y estructuras de embalaje son razones comunes. La desactivación de advertencias específicas es particularmente útil si compila con las advertencias como bandera de errores activada.

#pragma pack específicamente se usa para indicar que la estructura que se está empaquetando no debe tener sus miembros alineados. Es útil cuando tiene una interfaz mapeada en la memoria para una pieza de hardware y necesita poder controlar exactamente dónde apuntan los diferentes miembros de la estructura. En particular, no es una buena optimización de velocidad, ya que la mayoría de las máquinas son mucho más rápidas al tratar con datos alineados.