2010-04-19 10 views
13

Mogę użyć __LINE__ jako parametru metody dobrze, ale chciałbym w łatwy sposób użyć go w funkcji, która używa ciągów.Jak mogę użyć stałej czasowej kompilacji __LINE__ w ciągu znaków?

Na przykład, że mam to:

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

I chcę wynikiem funkcji będzie:

"myTest linia 14: testcondition failed"

Jak czy mogę napisać logError? Czy to musi być jakaś monstrualna makra?

Odpowiedz

27

Dlaczego potrzebujesz go jako ciąg? Co jest nie tak z liczbą całkowitą? Oto dwa sposoby, można napisać logError():

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

Jeśli naprawdę potrzebujesz linię jako ciąg, można użyć operatora stringizing #, ale ze względu na sposób pracy makra, trzeba zawinąć go w dwa makra:

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

a teraz LINE_STRING jest makro, które będą rozwijać się ciąg zawierający bieżący numer linii gdzie jest rozwinięty. Jeśli masz tylko jeden poziom makr (tzn. Jeśli masz #define STRINGIZE(x) #x), otrzymasz literalny ciąg "__LINE__" za każdym razem, gdy go rozszerzysz, co nie jest tym, czego potrzebujesz.

+3

Podczas gdy jest to stary wątek, powód, dla którego chciałbyś go użyć jako ciąg, w którym nie można użyć fprintf(). Jedno z takich miejsc znajduje się w procedurze obsługi sygnału, ponieważ fprintf() nie jest bezpieczny do użycia w procedurach obsługi sygnałów, gdy write() jest. – Bob9630

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

powinien zrobić to w stylu c. Wiem, że istnieją sposoby i sposoby robienia tego z bibliotekami ciągów C++.

Do tego celu można również użyć funkcji strcat() lub strncat lub dowolnej innej biblioteki Cb.

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

będzie działać również.

+0

Celem nie jest wyprowadzenie go na ekran, ale zwrócenie ciągu znaków z danymi zapisu. –

+1

Dlaczego nie po prostu 'cout <<" Łańcuch "<< __LINE__ <<" Inny ciąg znaków ";'? Nie ma potrzeby rzucania ani łączenia. –

+0

@John: To nie jest jasne z twojego pytania. –

2

Tak, jest brzydka. Potrzebujesz kombinacji makr. Konwersja liczby całkowitej na ciąg jest procesem dwuetapowym - oto realizacja Boost za:

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

Teraz można wygenerować ciąg:

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

nie ma powodu, aby wykonywać żadnej pracy run-to czasu :

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

Lub:

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

Jeśli jesteś osobą taką jak James.

+7

Lub, jeśli pogardzasz słowem "STRINGIZE", możesz użyć "STRINGIFICATE" i cieszyć się dziwnymi spojrzeniami od swoich współpracowników. –

+2

@ James: Należono zauważyć. – GManNickG

+1

Używam do tego słowa "stringify" :) –

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

Zastosowanie:

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

Następnie można utworzyć makro, za to jeśli były tak skłonne:

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

A potem użycie byłoby:

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

Spróbuj tego?

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

Twój logError nie zwraca łańcucha. –

6

Jego celem jest stworzenie makro (o nazwie logError), który będzie automatycznie zawierać symbole konieczne i wykonaj konkatenacji ciągów w preprocesora, tylko za pomocą literałów ciągów.

Więc, łącząc w zasadzie-poprawnych odpowiedzi odpowiedzi do tej pory, niech napisać makra:

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

Następnie można użyć tego makra nigdzie stworzyć ogólny błąd kod komunikatu STRING dosłownej formie w czasie kompilacji.

Uwaga: Można również użyć __FUNCTION__ (lub odpowiednika, różni się w zależności od kompilatora) zamiast __FILE__, jeśli wolisz, aby śledzić nazwę funkcji zamiast nazwy pliku.

Powiązane problemy