我使用snprintf
使用用户定义的格式(也以字符串形式给出)格式化字符串。代码如下所示:
void DataPoint::valueReceived( QVariant value ) {
// Get the formating QVariant, which is only considered valid if it's string
QVariant format = this->property("format");
if( format.isValid() && format.type()==QMetaType::QString && !format.isNull() ) {
// Convert QString to std string
const std::string formatStr = format.toString().toStdString();
LOGMTRTTIINFO(pointName<<"="<<value.toString().toUtf8().constData()<<"=>"<<formatStr<<"["<<formatStr.length()<<'\n');
// The attempt to catch exceptions caused by invalid formating string
try {
if( value.type() == QMetaType::QString ) {
// Treat value as string (values are allways ASCII)
const std::string array = value.toString().toStdString();
const char* data = (char*)array.c_str();
// Assume no more than 10 characters are added during formating.
char* result = (char*)calloc(array.length()+10, sizeof(char));
snprintf(result, array.length()+10, formatStr.c_str(), data);
value = result;
}
// If not string, then it's a number.
else {
double data = value.toDouble();
char* result = (char*)calloc(30, sizeof(char));
// Even 15 characters is already longer than largest number you can make any sense of
snprintf(result, 30, formatStr.c_str(), data);
LOGMTRTTIINFO(pointName<<"="<<data<<"=>"<<formatStr<<"["<<formatStr.length()<<"]=>"<<result<<'\n');
value = result;
}
} catch(...) {
LOGMTRTTIERR("Format error in "<<pointName<<'\n');
}
}
ui->value->setText(value.toString());
}
如你所见,我认为会有一些例外。但是没有,无效的格式化字符串会导致乱码。如果我尝试使用double
格式%s
:
那么有没有办法检测到选择了无效格式化选项,例如将数字格式化为字符串,反之亦然?如果给出完全无效的格式化字符串怎么办?
答案 0 :(得分:3)
你问是否可以在运行时检测格式/参数不匹配,对吧?然后,简短且唯一的答案是 否 。
要扩展“no”,因为Variable-argument函数(使用省略号...
的函数)没有类型安全性。编译器会将某些类型的参数转换为其他参数(例如char
或short
将转换为int
,float
将转换为double
),以及如果你使用文字字符串作为格式,一些编译器将能够解析字符串并检查你传递的参数。
但是,由于传递的变量字符串可以在运行时更改,因此编译器不可能进行任何类型的编译时检查,并且函数必须相信传递的格式字符串使用的是正确的格式。参数传递。如果不是那么你有未定义的行为。
答案 1 :(得分:1)
snprintf
失败后会发生什么?
当snprintf
失败时,POSIX要求设置errno:
如果遇到输出错误,这些函数将返回负值并设置errno以指示错误。
您还可以找到有关如何处理snprintf
失败Here的一些相关信息。