2010-04-19 12 views
13

Puedo usar __LINE__ como un parámetro de método muy bien, pero me gustaría una manera fácil de usarlo en una función que utiliza cadenas.¿Cómo puedo usar la constante de tiempo de compilación __LINE__ en una cadena?

Por ejemplo decir que tengo esto:

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

Y quiero que el resultado de la función de ser:

"myTest línea 14: testcondition falló"

Cómo puedo escribir logError? ¿Tiene que ser una monstruosidad de una macro?

Respuesta

27

¿Por qué incluso lo necesita como cuerda? ¿Qué pasa con un número entero? Aquí hay dos formas en las que podría escribir 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); 

Si realmente necesita la línea como una cadena, puede utilizar el operador stringizing #, pero debido a la forma en que funcionan las macros, que necesitará para envolverlo en dos macros:

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

Y ahora LINE_STRING es una macro que se expandirá a una cadena que contiene el número de línea actual donde quiera que se expande. Si solo tenía un nivel de macros (es decir, si tenía #define STRINGIZE(x) #x), obtendría la cadena literal "__LINE__" cada vez que la expandiera, que no es lo que desea.

+3

Si bien, este es un hilo antiguo, una razón por la que lo querría como una cadena como instancias donde no puede usar fprintf(). Uno de esos lugares está en un manejador de señales ya que fprintf() no es seguro para usar en manejadores de señal mientras que write() sí lo es. – Bob9630

3

Las opciones habituales para dar formato a un número en una cadena aplican: lexical_cast Boost, ostringstream, sprintf o snprintf, etc.

Aquí está uno de mis enlaces favoritos sobre el tema: http://www.gotw.ca/publications/mill19.htm

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

debería hacerlo c estilo. Sé que hay formas y maneras de hacerlo con las librerías de cadenas C++.

También podría usar strcat() o strncat o cualquier otra cantidad de bibliotecas C para hacer esto.

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

funcionarán también.

+0

El objetivo no es enviarlo a la pantalla sino devolver una cadena con los datos de escritura. –

+1

¿Por qué no simplemente 'cout <<" Cadena "<< __LINE__ <<" Otra cadena ";'? No hay necesidad de lanzar o concatenar. –

+0

@John: No está claro a partir de su pregunta. –

2

Sí, es feo. Necesitas una combinación de macros. La conversión de un entero a una cadena es un proceso de dos pasos - aquí está la implementación de Boost:

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

Ahora puede generar una cadena:

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

No hay razón para hacer cualquier trabajo en tiempo de ejecución para este :

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

O:

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

Si eres una persona genial como James.

+7

O, si desprecias la palabra "STRINGIZE", puedes usar "STRINGIFICATE" y disfrutar de las miradas raras de tus compañeros de trabajo. –

+2

@James: debidamente anotado. – GManNickG

+1

Uso la palabra "stringify" para eso :) –

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

Uso:

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

A continuación, puede hacer una macro para esto si gastronómica así:

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

Y a continuación, el uso sería:

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

¿Probar esto?

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

Su logError no devuelve una cadena. –

6

Su objetivo es crear una macro (llamado logError) que incluirá automáticamente los símbolos necesarios y hacer la concatenación de cadenas dentro del preprocesador, utilizando sólo los literales de cadena.

Por lo tanto, la combinación de las respuestas básicamente-respuestas correctas hasta el momento, vamos a escribir la macro:

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

A continuación, puede utilizar esta macro en cualquier lugar para crear un código de mensaje de error genérico en formato literal de cadena en tiempo de compilación.

Nota: También puede usar __FUNCTION__ (o un equivalente, varía según el compilador) en lugar de __FILE__, si lo prefiere, para realizar un seguimiento del nombre de la función en lugar del nombre del archivo.

Cuestiones relacionadas