Uso di #pragma in C


117

Quali sono alcuni usi di #pragmain C, con esempi?


2
#pragmala direttiva sopravvive alla fase di pre-elaborazione. A differenza di #includee #define.
smwikipedia


@smwikipedia intendi che sopravvivono alcuni pragmi? #pragma once è una direttiva del preprocessore ma #pragma pack è una direttiva del compilatore
Lewis Kelsey

Risposte:


66

#pragma è per le direttive del compilatore che sono specifiche della macchina o del sistema operativo, cioè dice al compilatore di fare qualcosa, impostare qualche opzione, intraprendere un'azione, sovrascrivere alcune impostazioni predefinite, ecc. che possono o non possono applicarsi a tutte le macchine e al funzionamento sistemi.

Vedi msdn per maggiori informazioni.


11
"che può o non può essere applicato a tutte le macchine e sistemi operativi." - e diversi compilatori sulla stessa macchina. E questo potrebbe significare cose diverse su compilatori diversi.
Steve Jessop

53

#pragma è usato per fare qualcosa di specifico per l'implementazione in C, cioè essere pragmatico per il contesto attuale piuttosto che ideologicamente dogmatico.

Quello che uso regolarmente è #pragma pack(1)dove sto cercando di spremere di più dal mio spazio di memoria su soluzioni embedded, con array di strutture che altrimenti finirebbero con un allineamento di 8 byte.

Peccato che non ne abbiamo #dogmaancora. Sarebbe divertente ;)


@ShaneMacLaughlin, Actully non pragma(1)migliora anche la velocità? Vedere stackoverflow.com/questions/3318410/...
Pacerier

4
@Pacerier, in genere no. Come da commenti jalfs, i dati allineati su un limite di 4 byte per i processori a 32 bit o su un limite di 8 byte per i processori a 64 bit verranno generalmente caricati e archiviati in un'unica operazione. I dati allineati su limiti più piccoli richiederanno più operazioni per il caricamento o l'archiviazione. Questo è più lento.
SmacL

35

In genere cercherò di evitare l'uso di #pragmas se possibile, poiché sono estremamente dipendenti dal compilatore e non portabili. Se vuoi usarli in modo portatile, dovrai circondare ogni pragma con una coppia #if/ #endif. GCC scoraggia l'uso di pragmi e in realtà ne supporta solo alcuni per compatibilità con altri compilatori; GCC ha altri modi per fare le stesse cose per cui altri compilatori usano i pragmi.

Ad esempio, ecco come assicurarti che una struttura sia ben compatta (ovvero senza riempimento tra i membri) in MSVC:

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

Ecco come faresti la stessa cosa in GCC:

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

Il codice GCC è più portabile, perché se vuoi compilarlo con un compilatore non GCC, tutto ciò che devi fare è

#define __attribute__(x)

Considerando che se vuoi portare il codice MSVC, devi circondare ogni pragma con una coppia #if/ #endif. Non carino.


3
Quindi, se voglio compilare il codice GCC su MSVC e ho bisogno di impacchettare la struttura, come lo faccio esattamente?
SmacL

2
Per gcc, è struct __attribute__((__packed__)) PackedStructure
Laurent Debricon,

#pragma once non è realisticamente "dipendente dal compilatore e non portabile". È supportato su tutte le piattaforme principali e su molte piattaforme non importanti .. en.wikipedia.org/wiki/Pragma_once#Portability
xaxxon

1
Notare che C99 e C11 contengono entrambi (C11) §6.10.6 direttive Pragma e ¶1 Qualsiasi pragma di questo tipo che non è riconosciuto dall'implementazione viene ignorato. Anche C90 dice che, sebbene fosse nella sezione §6.8.6. (Questo rende GCC non conforme se viene eseguito hackquando incontra un pragma che non riconosce, come faceva una volta molto, molto tempo fa - vedi #pragmae GCC , ecc.)
Jonathan Leffler

15

Mettere #pragma oncein cima al file di intestazione assicurerà che venga incluso solo una volta. Nota che #pragma oncenon è C99 standard, ma supportato dalla maggior parte dei compilatori moderni.

Un'alternativa è usare include guards (eg #ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */)


7

quello che sento è #pragmauna direttiva in cui se vuoi che il codice sia specifico per la posizione, dì una situazione in cui vuoi che il contatore del programma legga dall'indirizzo specifico in cui è scritto l'ISR, puoi specificare l'ISR in quella posizione usando #pragma vector=ADC12_VECTORe seguito da interrompi il nome delle rotine e la sua descrizione


5

Il mio miglior consiglio è di guardare la documentazione del compilatore, perché i pragmi sono per definizione specifici dell'implementazione. Ad esempio, nei progetti incorporati li ho usati per individuare codice e dati in diverse sezioni o dichiarare gestori di interrupt. vale a dire:

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler

3
Tutti i pragma sono specifici dell'implementazione, tranne i pragma #pragma STDC ..., che sono standardizzati su tutte le piattaforme (oltre a C99).
Jonathan Leffler

4

Tutte le risposte sopra sono belle spiegazioni #pragmama volevo aggiungere un piccolo esempio

Voglio solo spiegare un simple OpenMP exampleche dimostra alcuni usi #pragmaper fare il suo lavoro

OpenMp brieflyè un'implementazione per la programmazione parallela multipiattaforma a memoria condivisa (quindi possiamo dire che è machine-specifico operating-system-specific)

andiamo all'esempio

#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);
   }
}

l'uscita è

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.

ora lascia che ti dica cosa ha #pragmafatto ...

dice al sistema operativo di eseguire alcuni blocchi di codice su 4 thread

questo è solo uno di many many applicationsvoi che potete fare con il poco#pragma

scusa per il campione esterno OpenMP


3

Questa è una direttiva del preprocessore che può essere utilizzata per attivare o disattivare determinate funzionalità.

Si tratta di due tipi #pragma startup, #pragma exite #pragma warn.

#pragma startup ci permette di specificare le funzioni chiamate all'avvio del programma.

#pragma exit ci permette di specificare le funzioni chiamate all'uscita dal programma.

#pragma warn dice al computer di sopprimere o meno qualsiasi avviso.

Molti altri #pragmastili possono essere usati per controllare il compilatore.


3

#pragma startup è una direttiva che viene utilizzata per chiamare una funzione prima della funzione principale e per chiamare un'altra funzione dopo la funzione principale, ad es

#pragma startup func1
#pragma exit func2

Qui func1corre prima maine func2corre dopo.

NOTA: questo codice funziona solo nel compilatore Turbo-C. Per ottenere questa funzionalità in GCC, puoi dichiarare func1e in func2questo modo:

void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();

2

Per riassumere, #pragmadice al compilatore di fare cose. Ecco un paio di modi in cui lo uso:

  • #pragmapuò essere utilizzato per ignorare gli avvisi del compilatore. Ad esempio, per far tacere GCC sulle dichiarazioni di funzioni implicite, puoi scrivere:

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

    Una versione precedente di lo libportablefa in modo portatile .

  • #pragma once, quando scritto all'inizio di un file di intestazione, farà sì che detto file di intestazione venga incluso una volta. libportable verifica il pragma una volta supportato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.