Ist es mit dem C / C ++ - Präprozessor möglich, Zeilen innerhalb einer Quelldatei entweder in ein Makro oder in einen zur Kompilierungszeit verfügbaren Wert zu zählen? Zum Beispiel kann ich ersetzen MAGIC1
, MAGIC2
und MAGIC3
in den folgenden, und den Wert 4 irgendwie erhält bei der Verwendung MAGIC3
?
MAGIC1 // can be placed wherever you like before the relevant
// lines - either right before them, or in global scope etc.
foo(); MAGIC2
bar(); MAGIC2
baz(); MAGIC2
quux(); MAGIC2
// ... possibly a bunch of code here; not guaranteed to be in same scope ...
MAGIC3
Anmerkungen:
- Compilerspezifische Erweiterungen der Funktionen des Präprozessors sind akzeptabel, aber unerwünscht.
- Wenn dies nur mit Hilfe einiger C ++ - Konstrukte möglich ist, im Gegensatz zu C, ist dies ebenfalls akzeptabel, aber unerwünscht (dh ich möchte etwas, das für C funktioniert).
- Natürlich kann dies durch Ausführen der Quelldatei über ein externes Prozessorskript erfolgen, aber das ist nicht das, was ich frage.
c++
c-preprocessor
einpoklum
quelle
quelle
__LINE__
, das die aktuelle Zeilennummer darstellt__COUNTER__
und / oderBOOST_PP_COUNTER
?int arr[MAGIC4]
um die Anzahl der Zeilen in einem zuvor gezählten Abschnitt meines Codes zu sagen und abzurufen .Antworten:
Es gibt das
__LINE__
Präprozessor-Makro, das Ihnen eine Ganzzahl für die Zeile gibt, auf der angezeigt wird. Sie können den Wert in einer Zeile und später in einer Zeile angeben und vergleichen.Wenn Sie das Auftreten von etwas anstelle
__COUNTER__
von Quellzeilen zählen möchten, ist dies möglicherweise eine nicht standardmäßige Option, die von einigen Compilern wie GCC und MSVC unterstützt wird.Ich habe den Anfangswert von genommen,
__COUNTER__
weil er möglicherweise zuvor in der Quelldatei oder in einem enthaltenen Header verwendet wurde.In C und nicht in C ++ gibt es Einschränkungen für konstante Variablen, daher
enum
kann stattdessen eine verwendet werden.Ersetzen der Konstante durch
enum
:quelle
__COUNTER__
ist in C oder C ++ nicht Standard. Wenn Sie wissen, dass es mit bestimmten Compilern funktioniert, geben Sie diese an.BEFORE
undAFTER
sind keine MakrosIch weiß, dass die Anforderung des OP die Verwendung von Makros ist, aber ich möchte eine andere Möglichkeit hinzufügen, bei der keine Makros verwendet werden.
In C ++ 20 wird die
source_location
Klasse eingeführt, die bestimmte Informationen zum Quellcode darstellt, z. B. Dateinamen, Zeilennummern und Funktionsnamen. Wir können das in diesem Fall ziemlich einfach verwenden.Und anschauliches Beispiel hier .
quelle
source_location
experimentieren in C ++ 20?source_location
ist jetzt offiziell Teil von C ++ 20. Überprüfen Sie hier . Ich konnte die Version des gcc-Compilers auf godbolt.org einfach nicht finden , die sie bereits im nicht experimentellen Sinne unterstützt. Können Sie bitte Ihre Aussage etwas näher erläutern ? Ich kann die Zeilenanzahl nur im selben Bereich verwenden wie die Zeilen, die ich gezählt habe .line_number_start
undline_number_end
in diesem Bereich nirgendwo anders. Wenn ich es woanders haben will, muss ich es zur Laufzeit weitergeben - was den Zweck zunichte macht.line_number_end
zur Kompilierungszeit außerhalb seines Geltungsbereichs nicht sichtbar. Korrigiere mich, wenn ich falsch liege.Der Vollständigkeit halber: Wenn Sie
MAGIC2
nach jeder Zeile hinzufügen möchten, können Sie Folgendes verwenden__COUNTER__
:https://godbolt.org/z/i8fDLx (kehrt zurück
3
)Sie können es wiederverwendbar machen, indem Sie die Start- und Endwerte von speichern
__COUNTER__
.Insgesamt ist dies allerdings sehr umständlich. Sie können auch keine Zeilen zählen, die Präprozessoranweisungen enthalten oder mit
//
Kommentaren enden . Ich würde__LINE__
stattdessen verwenden, siehe die andere Antwort.quelle
static_assert
?__COUNTER__
es anfangs immer noch Null ist, da andere Header usw. es möglicherweise verwenden.__COUNTER__
zweimal verwenden und die Differenz nehmen__COUNTER__
alleine wäre nicht erlaubt und es muss auf etwas erweitert werden oder es zählt nicht (ich kann mich nicht zu 100% an die Regeln erinnern).Eine etwas robustere Lösung, die unterschiedliche Zähler zulässt (solange sie sich nicht vermischen und
__COUNTER__
für andere Aufgaben nicht verwendet werden können):Dadurch werden die Implementierungsdetails ausgeblendet (obwohl sie in Makros ausgeblendet sind ...). Es ist eine Verallgemeinerung der Antwort von @ MaxLanghof. Beachten Sie, dass der
__COUNTER__
Wert ungleich Null sein kann, wenn wir eine Zählung starten.So wird es verwendet:
Dies ist auch C gültig - wenn Ihr Präprozessor dies unterstützt
__COUNTER__
.Arbeitet an GodBolt .
Wenn Sie C ++ verwenden, können Sie diese Lösung modifizieren , nicht einmal den globalen Namensraum verschmutzen - durch die Zähler Platzierung innerhalb
namespace macro_based_line_counts { ... }
odernamespace detail
etc.)quelle
Basierend auf Ihrem Kommentar können Sie eine Arraygröße (zur Kompilierungszeit) in C oder C ++ angeben
Wenn Sie
sizeof(array)
in den dazwischenliegenden Zeilen benötigen , können Sie es durch eine statische Variablenreferenz ersetzen (es sei denn, es muss unbedingt ein ganzzahliger konstanter Ausdruck sein), und ein optimierender Compiler sollte es genauso behandeln (die statische Variable muss nicht platziert werden) in Erinnerung)Eine
__COUNTER__
Lösung auf Basis (falls diese Erweiterung verfügbar ist) im Gegensatz zu einer Lösung auf__LINE__
Basis funktioniert genauso.constexpr
s in C ++ sollte genauso gut funktionieren wieenum
,enum
funktioniert aber auch in einfachem C (meine obige Lösung ist eine einfache C-Lösung).quelle
__COUNTER__
basierte Lösung hat auch Probleme: Sie hoffen besser, dass Ihr magisches Makro der einzige Benutzer von ist__COUNTER__
, zumindest bevor Sie mit der Verwendung von fertig sind__COUNTER__
. Das Problem__COUNTER__/__LINE__
beruht im Wesentlichen auf den einfachen Fakten, die Präprozessorfunktionen sind, und der Präprozessor arbeitet in einem Durchgang, sodass Sie einen ganzzahligen konstanten Ausdruck später nicht basierend auf__COUNTER__
/ zurückpatchen können__LINE__
. Die einzige Möglichkeit (zumindest in C) besteht darin, die Notwendigkeit zu vermeiden, z. B. indem Forward-Array-Deklarationen ohne Größe verwendet werden (unvollständig typisierte Array-Deklarationen).\
wirkt sich das nicht aus__LINE__
- wenn es einen Zeilenumbruch gibt,__LINE__
erhöht sich. Beispiel 1 , Beispiel 2 .