2014-07-23 11 views
10

Bei der Implementierung meines eigenen C11-Compilers versuche ich herauszufinden, wie genau das _Pragma Schlüsselwort/Operator zu handhaben ist. C11 §6.10.9 beschreibt _Pragma als einen Operator, so dass es möglich scheint, es mit Makros, d. H. #define _Pragma(x) SOME_OTHER_MACRO(x), neu zu definieren. Ferner sollte die Aussage #undef _Pragma keine Wirkung haben (unter der Annahme, keine vorherige #define von _Pragma). Dies ist ähnlich, wie Schlüsselwörter #define d, wie der alte VC++ Hack #define for if (0) ; else for sein können. Da der Operator _Pragma während der Übersetzungsphase 3, der gleichen Phase wie die Ausführung der Präprozessordirektiven, ausgewertet wird, ist jedoch nicht klar, ob dies eine Ausnahme ist. Der Standard erwähnt nicht, ob sein undefiniertes Verhalten _Pragma als Makroname verwendet._Pragma und Makrosubstitution

habe ich einige Tests mit GCC mit dem folgenden Code:

#define PRAGMA _Pragma 
PRAGMA("message \"hi\"") 

_Pragma ("message \"sup\"") 

#undef PRAGMA 

#undef _Pragma 
//#define _Pragma(x) 
_Pragma("message \"hello\"") 

Kompilieren mit gcc -std=c11 -pedantic -Wall -Wextra -c Ausgänge:

tmp.c:2:1: note: #pragma message: hi 
PRAGMA("message \"hi\"") 
^ 
tmp.c:4:1: note: #pragma message: sup 
_Pragma ("message \"sup\"") 
^ 
tmp.c:8:8: warning: undefining "_Pragma" [enabled by default] 
#undef _Pragma 
     ^
tmp.c:10:9: error: expected declaration specifiers or ‘...’ before string constant 
_Pragma("message \"hello\"") 
     ^

Wenn ich die Linie #undef _Alignof hinzufügen, GCC darüber nicht beschweren.

Dies deutet darauf hin, dass GCC implementiert _Pragma durch ein Makro (über die Warnmeldung), und dass die Undefiniert es zu einem Kompilierungsfehler führt. Wenn ich #define _Pragma(x) auskommentiere, verschwindet der Fehler (wenn das Zeichenfolgenliteral verschwindet).

Also, meine Fragen sind:

  1. Dürfen Implementierungen _Pragma als nur ein Makro, und nicht implementieren sie als Operator definieren?
  2. Wenn nicht, ist GCC falsch dabei?
  3. Wenn _Pragma ein Operator sein soll, ist es undefiniertes Verhalten, _Pragma als Makro zu definieren?
  4. Gibt es eine Bestellung zwischen _Pragma Auswertung und anderen Präprozessordirektiven? Oder haben sie den gleichen "Vorrang" (d. H. Sie werden in der Reihenfolge bewertet)?

Wieder durch den C11-Standard suchen erwähnen nichts über _Pragma anders als es ein Operator ist, der für #pragma Richtlinien verwendet werden können.

+2

Antizipieren einige erhebliche Ebene der Meinung wird eine Rolle in den Antworten spielen Sie diese Frage zu bekommen, (wie die 'void main (void)' Diskussionen) jedoch Ihre Forschung ist offensichtlich, und Ihre Fragen werden gut präsentiert. Sollte zu interessanten Antworten führen.(+1) – ryyker

+0

Ich bin mir nicht sicher, ob ich den Standard hier richtig verstehe, aber ich denke, C11 7.1.3 p3 gilt: "Wenn das Programm (mit #undef) irgendeine Makrodefinition eines Bezeichners in der ersten Gruppe entfernt Wie oben erwähnt, ist das Verhalten nicht definiert. "Bei der erwähnten" ersten Gruppe "handelt es sich um Bezeichner, die mit einem Unterstrich gefolgt von einem weiteren Unterstrich oder einem Großbuchstaben beginnen. – mafso

+0

@mafso, die nur scheint zu gelten, wenn es in erster Linie eine Makro-Definition ist, so Code wie '#ifndef _Pragma #undef _Pragma # endif' würde nicht UB –

Antwort

5

Es gibt keine Notwendigkeit für eine spezielle Regel, die _Pragma verbieten würde, ein Makroname zu sein. Mit einem führenden Unterstrich und einem Großbuchstaben gehört er zu den reservierten Bezeichnern, die Sie sowieso nicht verwenden sollten. Die Verwendung von reservierten Bezeichnern führt zu undefiniertem Verhalten Ihres Programms, ein Compiler kann alles tun.

Eine Implementierung kann es als Makro implementieren, aber das sollte für Sie transparent sein, solange Sie es richtig verwenden, solange Sie nicht damit herumspielen. Die einzige wichtige Sache, die eine Implementierung garantieren muss, ist, dass die "Destringierung" und "Tokeninzierung" des Arguments zu der _Pragma erfolgt, als ob in Phase 3 (was schwierig ist, wenn es "nur" ein Makro ist) und dass die resultierende #pragma Richtlinie wird in Phase 4 verarbeitet.

+0

Es ist fast unklar, was der Standard bedeutet durch "reserviert für jede Verwendung" - sicherlich könnte eine Anweisung wie "int ln = __LINE __;" als eine Verwendung der Kennung "__LINE__" betrachtet werden (es sei denn, "für eine Verwendung reserviert" enthält keine obligatorischen Kennungen). –

+0

@DrewMcGowen: "für jede Verwendung reserviert" bedeutet, dass der Benutzer keine Kennungen dieses Formulars für irgendeine Verwendung deklarieren oder definieren kann (da es reserviert ist). Vergleichen Sie dies mit Bezeichnerformen, die nur für Bezeichner mit Dateiumfang reserviert sind oder nur wenn ein bestimmter Header enthalten ist. –

+1

@DrewMcGowen, dies hat eine sehr genaue Bedeutung, die in 7.1.3 zur Verfügung gestellt wird. Absatz 2 sagt, was Sie damit nicht tun sollten: * Wenn das Programm eine Kennung in einem Kontext deklariert oder definiert, in dem es reserviert ist (anders als in 7.1.4 erlaubt), oder definiert eine reservierte Kennung als a Makroname, das Verhalten ist nicht definiert. * –