可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I can use __LINE__
as a method parameter just fine, but I would like an easy way to use it in a function that uses strings.
For instance say I have this:
11 string myTest()
12 {
13 if(!testCondition)
14 return logError("testcondition failed");
15 }
And I want the result of the function to be:
"myTest line 14: testcondition failed"
How can I write logError? Does it have to be some monstrosity of a macro?
回答1:
Why do you even need it as a string? What's wrong with an integer? Here are two ways you could write 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);
If you really need the line as a string, you can use the stringizing operator #
, but because of the way macros work, you'll need to wrap it in two macros:
#define STRINGIZE(x) STRINGIZE2(x)
#define STRINGIZE2(x) #x
#define LINE_STRING STRINGIZE(__LINE__)
And now LINE_STRING
is a macro that will expand to a string containing the current line number wherever it is expanded. If you only had one level of macros (i.e. if you had #define STRINGIZE(x) #x
), then you would get the literal string "__LINE__"
every time you expanded it, which is not what you want.
回答2:
There's no reason to do any run-time work for this:
#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__) ".");
}
Or:
#define STOP_HAMMER_TIME(x) #x
#define STRINGIFICATE(x) STOP_HAMMER_TIME(x)
If you're a cool person like James.
回答3:
His goal is to create a macro (named logError) that will automatically include the symbols necessary and do the string concatenation within the preprocessor, only using string literals.
So, combining the basically-correct answers answers thus far, let's write the macro:
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define logError(msg) (__FILE__ " line " STRINGIZE(__LINE__) ": " msg)
You can then use this macro anywhere to create a generic error message code in string literal format at compile time.
Note: You can also use __FUNCTION__
(or an equivalent, it varies by compiler) instead of __FILE__
, if you prefer, to keep track of the function name instead of the file name.
回答4:
The usual options for formatting a number into a string apply: Boost lexical_cast, ostringstream, sprintf or snprintf, etc.
Here is one of my favorite links on the topic: http://www.gotw.ca/publications/mill19.htm
回答5:
Yes, it's ugly. You need a combination of macros. Converting an integer to a string is a two-step process - here's Boost's implementation:
#define BOOST_STRINGIZE(X) BOOST_DO_STRINGIZE(X)
#define BOOST_DO_STRINGIZE(X) #X
Now you can generate a string:
logError(__FILE__ BOOST_STRINGIZE(__LINE__) "testcondition failed");
回答6:
std::string logError(const char* file, int line, const char* msg)
{
std::ostringstream os;
os << file << ' ' << line << ':' << msg;
return os.str();
}
Usage:
return logError(__FILE__, __LINE__, "my error message");
You could then make a macro for this if you were so inclined:
#define LOG_ERROR(x) logError(__FILE__, __LINE__, (x))
And then the usage would be:
return LOG_ERROR("my error message");
回答7:
sprintf(newStringBuffer, "myTest line %d: testcondition failed\n", __LINE__);
should do it c style. I know that there are ways and ways of doing this with the C++ string libraries.
You could also use strcat() or strncat or any other number of C libs to do this.
cout <<"String" + __LINE__ + " another string"
will work as well.
回答8:
Try this?
string myTest(const int lineno)
{
if(!testCondition)
return logError ("testcondition failed", lineno);
}
void logError (string msg, const int lineno)
{
clog << "line " << lineno << ": " << msg << endl;
}