Verwendung von #pragma in C.


117

Was sind einige Verwendungszwecke #pragmain C mit Beispielen?


2
#pragmaDie Richtlinie überlebt die Vorverarbeitungsphase. Im Gegensatz zu #includeund #define.
smwikipedia

Mögliches Duplikat von Was bedeutet #pragma einmal in C?

@smwikipedia meinst du einige Pragmas überleben? #pragma einmal ist eine Präprozessor-Direktive, aber #pragma pack ist eine Compiler-Direktive
Lewis Kelsey

Antworten:


66

#pragma ist für Compiler-Direktiven gedacht, die maschinenspezifisch oder betriebssystemspezifisch sind, dh der Compiler wird angewiesen, etwas zu tun, eine Option festzulegen, Maßnahmen zu ergreifen, einige Standardeinstellungen zu überschreiben usw., die möglicherweise für alle Maschinen und den Betrieb gelten oder nicht Systeme.

Siehe msdn für weitere Informationen.


11
"Das kann für alle Maschinen und Betriebssysteme gelten oder nicht." - und verschiedene Compiler auf derselben Maschine. Und was auf verschiedenen Compilern unterschiedliche Bedeutungen haben könnte.
Steve Jessop

53

#pragma wird verwendet, um etwas Implementierungsspezifisches in C zu tun, dh für den aktuellen Kontext pragmatisch und nicht ideologisch dogmatisch zu sein.

Die, die ich regelmäßig verwende, ist der, #pragma pack(1)bei dem ich versuche, bei eingebetteten Lösungen mit Arrays von Strukturen, die sonst zu einer 8-Byte-Ausrichtung führen würden, mehr aus meinem Speicherplatz herauszuholen.

Schade, dass wir noch keine haben #dogma. Das würde Spaß machen ;)


@ShaneMacLaughlin, pragma(1)Verbessert die Geschwindigkeit nicht auch wirklich? Siehe stackoverflow.com/questions/3318410/…
Pacerier

4
@ Pacerier, normalerweise nicht. Gemäß den Jalfs-Kommentaren werden Daten, die an einer 4-Byte-Grenze für 32-Bit-Prozessoren oder einer 8-Byte-Grenze für 64-Bit-Prozessoren ausgerichtet sind, normalerweise in einer einzigen Operation geladen und gespeichert. Daten, die an kleineren Grenzen ausgerichtet sind, benötigen mehrere Vorgänge zum Laden oder Speichern. Das ist langsamer.
SmacL

35

Ich würde generell versuchen, die Verwendung von #pragmas möglichst zu vermeiden, da sie extrem compilerabhängig und nicht portabel sind. Wenn Sie sie tragbar verwenden möchten, müssen Sie jedes Pragma mit einem #if/ #endifPaar umgeben. GCC rät von der Verwendung von Pragmas ab und unterstützt nur einige davon aus Gründen der Kompatibilität mit anderen Compilern. GCC hat andere Möglichkeiten, die gleichen Dinge zu tun, für die andere Compiler Pragmas verwenden.

So stellen Sie beispielsweise sicher, dass eine Struktur in MSVC dicht gepackt ist (dh keine Auffüllung zwischen Mitgliedern):

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

So würden Sie in GCC dasselbe tun:

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

Der GCC-Code ist portabler, denn wenn Sie ihn mit einem Nicht-GCC-Compiler kompilieren möchten, müssen Sie nur etwas tun

#define __attribute__(x)

Wenn Sie den MSVC-Code portieren möchten, müssen Sie jedes Pragma mit einem #if/ #endifpair umgeben. Nicht hübsch.


3
Wenn ich also den GCC-Code auf MSVC kompilieren möchte und die Struktur packen muss, wie genau mache ich das?
SmacL

2
Für gcc ist es struct __attribute__((__packed__)) PackedStructure
Laurent Debricon

#pragma einmal ist nicht realistisch "compilerabhängig und nicht portabel". Es ist auf alle wichtigen Plattform unterstützt und viele nicht-großen Plattformen .. en.wikipedia.org/wiki/Pragma_once#Portability
xaxxon

1
Beachten Sie, dass sowohl C99 als auch C11 (C11) §6.10.6 Pragma-Anweisungen und ¶1 enthalten. Jedes solche Pragma, das von der Implementierung nicht erkannt wird, wird ignoriert. Sogar C90 sagt das, obwohl es in Abschnitt §6.8.6 war. (Dies macht GCC nicht konform, wenn es ausgeführt wird, hackwenn es auf ein Pragma stößt, das es nicht erkennt, wie es es vor sehr, sehr langer Zeit getan hat - siehe #pragmaund GCC usw.)
Jonathan Leffler

15

Wenn Sie #pragma onceoben in Ihre Header-Datei einfügen, wird sichergestellt, dass sie nur einmal enthalten ist. Beachten Sie, dass dies #pragma oncekein Standard-C99 ist, sondern von den meisten modernen Compilern unterstützt wird.

Eine Alternative ist die Verwendung Wachen sind (zB #ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */)


7

Was ich #pragmadenke, ist eine Direktive, in der, wenn Sie möchten, dass der Code ortsspezifisch ist. Sagen Sie eine Situation, in der der Programmzähler von der spezifischen Adresse lesen soll, an der der ISR geschrieben ist, dann können Sie den ISR an diesem Ort mit #pragma vector=ADC12_VECTORund gefolgt von angeben Interrupt dreht den Namen und seine Beschreibung


5

Mein bester Rat ist, sich die Dokumentation Ihres Compilers anzusehen, da Pragmas per Definition implementierungsspezifisch sind. In eingebetteten Projekten habe ich sie beispielsweise verwendet, um Code und Daten in verschiedenen Abschnitten zu suchen oder Interrupt-Handler zu deklarieren. dh:

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler

3
Alle Pragmas sind implementierungsspezifisch - mit Ausnahme der Pragmas #pragma STDC ..., die plattformübergreifend standardisiert sind (zusätzlich zu C99).
Jonathan Leffler

4

Alle obigen Antworten sind nette Erklärungen, #pragmaaber ich wollte ein kleines Beispiel hinzufügen

Ich möchte nur ein Beispiel erläutern simple OpenMP example, das einige Verwendungsmöglichkeiten für #pragmaseine Arbeit demonstriert

OpenMp brieflyist eine Implementierung für die parallele Programmierung von Shared-Memory mit mehreren Plattformen (dann können wir sagen, es ist machine-specificoder operating-system-specific)

Gehen wir zum Beispiel

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

die Ausgabe ist

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.

Jetzt lass mich dir sagen, was #pragma...

Es weist das Betriebssystem an, den Codeblock auf 4 Threads auszuführen

Dies ist nur einer von many many applicationseuch, der mit dem Kleinen etwas anfangen kann#pragma

Entschuldigung für die äußere Probe OpenMP


3

Dies ist eine Präprozessoranweisung, mit der bestimmte Funktionen ein- oder ausgeschaltet werden können.

Es ist von zwei Arten #pragma startup, #pragma exitund #pragma warn.

#pragma startup ermöglicht es uns, Funktionen anzugeben, die beim Programmstart aufgerufen werden.

#pragma exit ermöglicht es uns, Funktionen anzugeben, die beim Beenden des Programms aufgerufen werden.

#pragma warn Weist den Computer an, jede Warnung zu unterdrücken oder nicht.

Viele andere #pragmaStile können verwendet werden, um den Compiler zu steuern.


3

#pragma startup ist eine Direktive, mit der eine Funktion vor der Hauptfunktion und eine andere Funktion nach der Hauptfunktion aufgerufen wird, z

#pragma startup func1
#pragma exit func2

Hier func1läuft vorher mainund func2läuft danach.

HINWEIS: Dieser Code funktioniert nur im Turbo-C-Compiler. Um diese Funktionalität in GCC zu erreichen, können Sie Folgendes deklarieren func1und func2mögen:

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

2

Um es zusammenzufassen, #pragmaweist er den Compiler an, Dinge zu tun. Hier sind einige Möglichkeiten, wie ich es benutze:

  • #pragmakann verwendet werden, um Compiler-Warnungen zu ignorieren. Um beispielsweise GCC wegen impliziter Funktionsdeklarationen zum Schweigen zu bringen, können Sie Folgendes schreiben:

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

    Eine ältere Version von libportablemacht dies portabel .

  • #pragma onceWenn diese Header-Datei oben in eine Header-Datei geschrieben wird, wird sie einmal eingefügt. libportable prüft auf Pragma einmal Unterstützung.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.