2010-04-19 6 views
13

Ich kann __LINE__ als Methodenparameter einfach verwenden, aber ich möchte eine einfache Möglichkeit, es in einer Funktion, die Zeichenfolgen verwendet.Wie kann ich die Kompilierzeitkonstante __LINE__ in einem String verwenden?

Zum Beispiel sagen, ich habe dies:

11 string myTest() 
12 { 
13  if(!testCondition) 
14  return logError("testcondition failed"); 
15 } 

Und ich möchte das Ergebnis der Funktion sein:

"myTest Linie 14: testcondition fehlgeschlagen"

Wie kann ich logError schreiben? Muss es eine Monstrosität eines Makros sein?

Antwort

27

Warum brauchen Sie es sogar als String? Was ist falsch an einer Ganzzahl? Hier sind zwei Möglichkeiten, wie Sie logError() schreiben konnte:

#define logError(str) fprintf(stderr, "%s line %d: %s\n", __FILE__, __LINE__, str) 

// Or, forward to a more powerful function 
#define logError(str) logError2(__FILE__, __LINE__, str) 
void logError2(const char *file, int line, const char *str); 

Wenn Sie wirklich die Zeile als String benötigen, können Sie den Zeichenfolgenoperator #, sondern wegen der Art und Weise Makros arbeiten, müssen Sie es wickeln in zwei Makros:

#define STRINGIZE(x) STRINGIZE2(x) 
#define STRINGIZE2(x) #x 
#define LINE_STRING STRINGIZE(__LINE__) 

Und jetzt LINE_STRING ist ein Makro, das in eine Zeichenfolge erweitert die aktuelle Zeilennummer enthält, wo es expandiert wird. Wenn Sie nur eine Ebene von Makros hätten (d. H. Wenn Sie #define STRINGIZE(x) #x hätten), dann würden Sie die Literalzeichenfolge "__LINE__" jedes Mal erhalten, wenn Sie sie erweitern, was nicht das ist, was Sie wollen.

+3

Dies ist ein alter Thread, ein Grund, warum Sie wollen, dass es als eine Zeichenfolge als Instanzen, wo Sie nicht fprintf() verwenden können. Ein solcher Ort befindet sich in einem Signal-Handler, da fprintf() für die Verwendung in Signal-Handlern nicht sicher ist, während write() dies ist. – Bob9630

3

die üblichen Optionen zur Formatierung einer Zahl in einen String anwenden: Boost lexical_cast, Ostringstream, sprintf oder snprintf usw.

Dies ist einer meiner Lieblings-Links zum Thema: http://www.gotw.ca/publications/mill19.htm

0
sprintf(newStringBuffer, "myTest line %d: testcondition failed\n", __LINE__); 

sollte es c Stil tun. Ich weiß, dass es Möglichkeiten und Möglichkeiten gibt, dies mit den C++ String-Bibliotheken zu tun.

Sie könnten auch strcat() oder strncat oder eine andere Anzahl von C-Bibliotheken verwenden, um dies zu tun.

cout <<"String" + __LINE__ + " another string" 

wird auch funktionieren.

+0

Das Ziel ist nicht, es auf dem Bildschirm auszugeben, sondern eine Zeichenkette mit den Daten zu schreiben. –

+1

Warum nicht nur 'cout <<" String "<< __LINE__ <<" Eine andere Zeichenkette ";'? Keine Notwendigkeit zum Casting oder Verketten. –

+0

@John: Das ist nicht klar aus Ihrer Frage. –

2

Ja, es ist hässlich. Sie benötigen eine Kombination von Makros. eine ganze Zahl in einen String konvertiert wird ein zweistufiger Prozess - hier ist der Boost-Implementierung:

#define BOOST_STRINGIZE(X) BOOST_DO_STRINGIZE(X) 
#define BOOST_DO_STRINGIZE(X) #X 

Jetzt können Sie einen String erzeugen:

logError(__FILE__ BOOST_STRINGIZE(__LINE__) "testcondition failed"); 
24

Es gibt keinen Grund, jede Laufzeitarbeit, dies zu tun :

#include <iostream> 

// two macros ensures any macro passed will 
// be expanded before being stringified 
#define STRINGIZE_DETAIL(x) #x 
#define STRINGIZE(x) STRINGIZE_DETAIL(x) 

// test 
void print(const char* pStr) 
{ 
    std::cout << pStr << std::endl; 
} 

int main(void) 
{ 
    // adjacent strings are concatenated 
    print("This is on line #" STRINGIZE(__LINE__) "."); 
} 

Oder:

#define STOP_HAMMER_TIME(x) #x 
#define STRINGIFICATE(x) STOP_HAMMER_TIME(x) 

Wenn Sie eine coole Person wie James sind.

+7

Oder, wenn Sie das Wort "STRINGIZE" verachten, können Sie 'STRINGIFICATE' verwenden und seltsame Blicke von Ihren Mitarbeitern genießen. –

+2

@ James: Ordnungsgemäß notiert. – GManNickG

+1

Ich verwende das Wort "stringify" für das :) –

1
std::string logError(const char* file, int line, const char* msg) 
{ 
    std::ostringstream os; 
    os << file << ' ' << line << ':' << msg; 
    return os.str(); 
} 

Verbrauch:

return logError(__FILE__, __LINE__, "my error message"); 

Sie dann einen Makro für das machen könnte, wenn Sie so geneigt sind:

#define LOG_ERROR(x) logError(__FILE__, __LINE__, (x)) 

Und dann wäre die Nutzung sein:

return LOG_ERROR("my error message"); 
-2

Versuchen Sie das?

string myTest(const int lineno) 
{ 
    if(!testCondition) 
    return logError ("testcondition failed", lineno); 
} 

void logError (string msg, const int lineno) 
{ 
    clog << "line " << lineno << ": " << msg << endl; 
} 
+0

Ihr logError gibt keine Zeichenfolge zurück. –

6

Sein Ziel ist es, ein Makro (benannt logError) zu erstellen, die automatisch werden die Symbole notwendig und führen Sie die String-Verkettung innerhalb der Prä-Prozessor enthalten, nur Zeichenfolgenliterale verwenden.

also die Kombination der im Grunde richtigen Antworten so weit beantwortet, lassen Sie sich das Makro schreiben:

#define STRINGIZE_DETAIL(x) #x 
#define STRINGIZE(x) STRINGIZE_DETAIL(x) 
#define logError(msg) (__FILE__ " line " STRINGIZE(__LINE__) ": " msg) 

Anschließend können Sie dieses Makro überall verwenden, um einen generische Fehlermeldung Code in Stringliteral Format bei der Kompilierung zu erstellen.

Hinweis: Sie können auch __FUNCTION__ (oder eine gleichwertige, variiert nach Compiler) anstelle von __FILE__, wenn Sie bevorzugen, um den Funktionsnamen anstelle des Dateinamens zu verfolgen.

Verwandte Themen