我正在尝试完成我的日志记录类。我从头开始编写它,不希望使用任何类型的替代库。我的问题在于我的记录器在输出std::string
时遇到问题,只有当我用string.c_str()
函数表示它时才有效。
这是我的日志文件输出功能:
void Log::writeSuccess(char * text,...)
{
// Grab the variables and insert them
va_list ap;
va_start(ap, text);
char buff[BUFFER_SIZE];
vsnprintf(buff, sizeof(buff), text, ap);
// Output to the log
logfile << "<-!-> " << buff << endl;
}
以下是对我的日志类对象的示例调用(忽略调用的无用性):
string test("This is a test string!");
errorLog.writeSuccess("Output: %s", test);
我最终得到随机字符和输出乱码。
但是,当我将test
附加.c_str()
字符串时,它会正确输出文字。
我试图避免使用cstrings的全部原因是因为我知道它们不是跨平台的,我正在开发我的客户端来支持所有主要的操作系统。
总结:
我的日志输出功能有什么问题?你认为有什么方法可以改进吗?
我一般应该避免使用c_strings吗?
答案 0 :(得分:2)
在将std::string
传递给vsnprintf
时,您会发现随机乱码,因为格式说明符"%s"
是C字符串 - char*
。
std::string
类型为char*
,但std::string.c_str()
类型为char*
。 vsnprintf
基本上会读取{em>它假定的地址所指向的char
是C字符串的开头,直到NUL字符'\0'
为止
将std::string
推入堆栈并作为参数传递给vsnprintf
不是指向char
的指针,但是vsnprintf
只会将这些字节视为地址并从该地址开始读取char
s / bytes,导致未定义的行为。
printf
函数族不是类型安全的,因为它们依赖于格式字符串和变量参数列表,这就是为什么你的代码会编译但你会得到意想不到的结果。
当您使用格式说明符printf
时,底线是期望char*
的{{1}}系列函数。
我还认为你将C样式字符串("%s"
)与特定于Microsoft的CString
类混淆。 C样式字符串根本不会在不同平台上引起问题;文字char[]
是C样式字符串("This is a test string!"
)。
答案 1 :(得分:1)
使用变量参数调用函数时,必须使用简单类型。对于string
,您必须使用c_str()
。没有解决方法。 MFC的CString
旨在让您可以直接使用它,但这是微软的决定,也是他们设计的一部分。
编辑:正如我在调用具有可变参数的函数时所说,必须使用string :: c_str()。但是,您可以使用类似boost::format()
之类的函数来代替具有可变参数的类似C函数,并使用参数提供运算符%。这也使您可以更好地控制参数的排序,这对i18n非常方便。