Я могу использовать __LINE__
как параметр метода очень хорошо, но я хотел бы простой способ использовать его в функции, которая использует строки.
Например, скажите, что у меня есть это:
11 string myTest()
12 {
13 if(!testCondition)
14 return logError("testcondition failed");
15 }
И я хочу, чтобы результат функции был:
"строка myTest 14: testcondition перестал работать"
Как я могу записать logError? Это должно быть некоторое чудовище макроса?
Зачем он вообще нужен в виде струны? Что не так с целым числом? Вот два способа записать 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);
Если вам действительно нужна строка в виде строки, вы можете использовать оператор строкового преобразования #
, но из-за способа использования макросов работы, вам нужно будет заключить его в два макроса:
#define STRINGIZE(x) STRINGIZE2(x)
#define STRINGIZE2(x) #x
#define LINE_STRING STRINGIZE(__LINE__)
И теперь LINE_STRING
- это макрос, который будет расширяться до строки, содержащей текущий номер строки, где бы он ни был развернут. Если бы у вас был только один уровень макросов (например, если бы у вас был #define STRINGIZE (x) #x
), вы бы получали буквальную строку «__ LINE __»
каждый раз, когда расширяли его. , а это не то, что вам нужно.
Нет причин выполнять какую-либо работу во время выполнения для этого:
#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__) ".");
}
Или:
#define STOP_HAMMER_TIME(x) #x
#define STRINGIFICATE(x) STOP_HAMMER_TIME(x)
Если ты такой крутой человек, как Джеймс.
Да, это некрасиво. Вам нужна комбинация макросов. Преобразование целого числа в строку - это двухэтапный процесс - здесь реализация Boost:
#define BOOST_STRINGIZE(X) BOOST_DO_STRINGIZE(X)
#define BOOST_DO_STRINGIZE(X) #X
Теперь вы можете сгенерировать строку:
logError(__FILE__ BOOST_STRINGIZE(__LINE__) "testcondition failed");
Попробовать?
string myTest(const int lineno)
{
if(!testCondition)
return logError ("testcondition failed", lineno);
}
void logError (string msg, const int lineno)
{
clog << "line " << lineno << ": " << msg << endl;
}
std::string logError(const char* file, int line, const char* msg)
{
std::ostringstream os;
os << file << ' ' << line << ':' << msg;
return os.str();
}
Использование:
return logError(__FILE__, __LINE__, "my error message");
Вы могли бы затем создать макрос для этого, если бы вы были так склонны:
#define LOG_ERROR(x) logError(__FILE__, __LINE__, (x))
И тогда использование было бы следующим:
return LOG_ERROR("my error message");
Применяются обычные варианты форматирования числа в строку: Boost lexical_cast, ostringstream, sprintf или snprintf и т. Д.
Вот одна из моих любимых ссылок по теме: http: //www.gotw .ca / публикации / mill19.htm
sprintf(newStringBuffer, "myTest line %d: testcondition failed\n", __LINE__);
должен делать это в стиле c. Я знаю, что есть способы и способы сделать это с помощью строковых библиотек C ++.
Вы также можете использовать strcat () или strncat или любое другое количество библиотек C для этого.
cout <<"String" + __LINE__ + " another string"
также будет работать.
Его цель - создать макрос (с именем logError ), который будет автоматически включать необходимые символы и выполнять конкатенацию строк в препроцессоре. , используя только строковые литералы.
Итак, объединив до сих пор в основном правильные ответы, давайте напишем макрос:
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define logError(msg) (__FILE__ " line " STRINGIZE(__LINE__) ": " msg)
Затем вы можете использовать этот макрос где угодно, чтобы создать общий код сообщения об ошибке в формате строкового литерала во время компиляции.
Примечание. Вы также можете использовать __ FUNCTION __
(или эквивалент, зависит от компилятора) вместо __ FILE __
, если хотите, чтобы отслеживать имя функции вместо имя файла.