Uso de #pragma en C

117

¿Cuáles son algunos usos de #pragmaen C, con ejemplos?

MD XF
fuente
2
#pragmadirectiva sobrevive a la etapa de preprocesamiento. A diferencia de #includey #define.
smwikipedia
@smwikipedia, ¿te refieres a que algunos pragmas sobreviven? #pragma once es una directiva de preprocesador, pero #pragma pack es una directiva de compilador
Lewis Kelsey

Respuestas:

66

#pragma es para las directivas del compilador que son específicas de la máquina o del sistema operativo, es decir, le dice al compilador que haga algo, establezca alguna opción, tome alguna acción, anule algunos valores predeterminados, etc.que pueden o no aplicarse a todas las máquinas y operaciones sistemas.

Consulte msdn para obtener más información.

Steven A. Lowe
fuente
11
"Eso puede aplicarse o no a todas las máquinas y sistemas operativos". - y diferentes compiladores en la misma máquina. Y lo que puede significar cosas diferentes en diferentes compiladores.
Steve Jessop
53

#pragma se utiliza para hacer algo específico de implementación en C, es decir, ser pragmático para el contexto actual en lugar de ideológicamente dogmático.

El que uso habitualmente es el #pragma pack(1)que trato de sacar más provecho de mi espacio de memoria en soluciones integradas, con matrices de estructuras que, de otro modo, terminarían con una alineación de 8 bytes.

Lástima que no tengamos #dogmatodavía. Eso sería divertido ;)

SmacL
fuente
@ShaneMacLaughlin, ¿No pragma(1)mejora realmente la velocidad también? Ver stackoverflow.com/questions/3318410/…
Pacerier
4
@Pacerier, normalmente no. Según los comentarios de jalfs, los datos que están alineados en un límite de 4 bytes para procesadores de 32 bits o un límite de 8 bytes para procesadores de 64 bits se cargarán y almacenarán normalmente en una sola operación. Los datos alineados en límites más pequeños requerirán múltiples operaciones para cargar o almacenar. Esto es más lento.
SmacL
35

En general, trataría de evitar el uso de #pragmas si es posible, ya que son extremadamente dependientes del compilador y no portátiles. Si desea usarlos de manera portátil, tendrá que rodear cada pragma con un #if/ #endifpair. GCC desaconseja el uso de pragmas y, en realidad, solo admite algunos de ellos por compatibilidad con otros compiladores; GCC tiene otras formas de hacer las mismas cosas para las que otros compiladores usan pragmas.

Por ejemplo, así es como se aseguraría de que una estructura esté compactada (es decir, sin relleno entre miembros) en MSVC:

#pragma pack(push, 1)
struct PackedStructure
{
  char a;
  int b;
  short c;
};
#pragma pack(pop)
// sizeof(PackedStructure) == 7

Así es como harías lo mismo en GCC:

struct PackedStructure __attribute__((__packed__))
{
  char a;
  int b;
  short c;
};
// sizeof(PackedStructure == 7)

El código GCC es más portátil, porque si desea compilarlo con un compilador que no sea GCC, todo lo que tiene que hacer es

#define __attribute__(x)

Mientras que si desea portar el código MSVC, debe rodear cada pragma con un #if/ #endifpair. No es bonito.

Adam Rosenfield
fuente
3
Entonces, si quiero compilar el código GCC en MSVC y necesito empaquetar la estructura, ¿cómo lo hago exactamente?
SmacL
2
Para gcc, es struct __attribute__((__packed__)) PackedStructure
Laurent Debricon
#pragma once no es realista "dependiente del compilador y no portátil". Se apoya en las principales plataformas y muchas plataformas no-principales .. en.wikipedia.org/wiki/Pragma_once#Portability
xaxxon
1
Tenga en cuenta que C99 y C11 contienen (C11) §6.10.6 directivas Pragma y ¶1 Cualquier pragma que no sea reconocido por la implementación se ignora. Incluso C90 dice eso, aunque estaba en la sección §6.8.6. (Esto hace que GCC no sea compatible si se ejecuta hackcuando encuentra un pragma que no reconoce, como solía hacer hace mucho, mucho tiempo, ver #pragmay GCC , etc.)
Jonathan Leffler
15

Ponerlo #pragma onceen la parte superior de su archivo de encabezado asegurará que solo se incluya una vez. Tenga en cuenta que #pragma onceno es C99 estándar, pero es compatible con la mayoría de los compiladores modernos.

Una alternativa es usar protectores incluidos (p #ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */. Ej. )

Schildmeijer
fuente
7

lo que siento es #pragmauna directiva en la que, si desea que el código sea específico de la ubicación, diga una situación en la que desea que el contador del programa lea desde la dirección específica donde está escrito el ISR, entonces puede especificar el ISR en esa ubicación usando #pragma vector=ADC12_VECTORy seguido de interrumpir el nombre de rotines y su descripción

sandeep
fuente
5

Mi mejor consejo es mirar la documentación de su compilador, porque los pragmas son, por definición, específicos de la implementación. Por ejemplo, en proyectos integrados los he usado para localizar código y datos en diferentes secciones, o declarar manejadores de interrupciones. es decir:

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler
Sólo en el amor
fuente
3
Todos los pragmas son específicos de la implementación, excepto los pragmas #pragma STDC ..., que están estandarizados en todas las plataformas (además de C99).
Jonathan Leffler
4

Todas las respuestas anteriores son buenas explicaciones, #pragmapero quería agregar un pequeño ejemplo

Solo quiero explicar un simple OpenMP exampleque demuestra algunos usos de #pragmapara hacer su trabajo.

OpenMp brieflyes una implementación para la programación paralela de memoria compartida multiplataforma (entonces podemos decir que es machine-specifico operating-system-specific)

vayamos al ejemplo

#include <stdio.h>
#include <omp.h>// compile with: /openmp

int main() {
   #pragma omp parallel num_threads(4)
   {
      int i = omp_get_thread_num();
      printf_s("Hello from thread %d\n", i);
   }
}

la salida es

Hello from thread 0
Hello from thread 1
Hello from thread 2
Hello from thread 3

Note that the order of output can vary on different machines.

ahora déjame decirte lo que #pragmahizo ...

le dice al sistema operativo que ejecute algún bloque de código en 4 subprocesos

esto es solo uno de many many applicationsustedes puede hacer con el pequeño#pragma

perdón por la muestra exterior OpenMP

Basheer AL-MOMANI
fuente
3

Se trata de una directiva de preprocesador que se puede utilizar para activar o desactivar determinadas funciones.

Es de dos tipos #pragma startup, #pragma exity #pragma warn.

#pragma startup nos permite especificar funciones llamadas al inicio del programa.

#pragma exit nos permite especificar funciones llamadas al salir del programa.

#pragma warn le dice a la computadora que elimine cualquier advertencia o no.

Se #pragmapueden usar muchos otros estilos para controlar el compilador.

seguro pareek
fuente
3

#pragma startup es una directiva que se utiliza para llamar a una función antes de la función principal y para llamar a otra función después de la función principal, por ejemplo

#pragma startup func1
#pragma exit func2

Aquí, func1corre antes mainy func2corre después.

NOTA: Este código solo funciona en el compilador Turbo-C. Para lograr esta funcionalidad en GCC, puede declarar func1y func2así:

void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();
Sparkzz
fuente
2

En resumen, #pragmale dice al compilador que haga cosas. Aquí hay un par de formas en que lo uso:

  • #pragmase puede utilizar para ignorar las advertencias del compilador. Por ejemplo, para hacer que GCC se calle sobre las declaraciones de funciones implícitas, puede escribir:

    #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"

    Una versión anterior de libportablehace esto de forma portátil .

  • #pragma once, cuando se escribe en la parte superior de un archivo de encabezado, hará que dicho archivo de encabezado se incluya una vez. libportable comprueba si hay pragma una vez compatible.

MD XF
fuente