将错误代码转换为要显示的字符串 < C++中有没有一种常见的方法将错误代码翻译成字符串来显示?
我在某个地方看到了一个带有大开关的将错误代码转换为要显示的字符串 < C++中有没有一种常见的方法将错误代码翻译成字符串来显示?,c++,C++,我在某个地方看到了一个带有大开关的err2msg函数,但这真的是最好的方法吗?在windows中,您可以使用FormatMessage(…)函数返回错误代码,或者直接返回可疑区域 请参阅下面的链接以获取示例 我希望这会对你有所帮助。这个大开关对你来说没那么坏。获取错误代码的字符串几乎总是对性能不重要的 您应该记住,这些错误字符串可能不是您想要向用户显示的内容。用户的信息应该保存在资源中,以便于翻译 错误代码字符串用于日志或诊断,无需翻译 您可以使用此技巧定义错误代码和Parralel中的字符
err2msg
函数,但这真的是最好的方法吗?在windows中,您可以使用FormatMessage(…)
函数返回错误代码,或者直接返回可疑区域
请参阅下面的链接以获取示例
我希望这会对你有所帮助。这个大开关对你来说没那么坏。获取错误代码的字符串几乎总是对性能不重要的 您应该记住,这些错误字符串可能不是您想要向用户显示的内容。用户的信息应该保存在资源中,以便于翻译 错误代码字符串用于日志或诊断,无需翻译 您可以使用此技巧定义错误代码和Parralel中的字符串:
#if defined(ERROR_BUILD_ARRAY)
#define ERROR_START \
static const err_defn error_table[] = { \
{ WARNING, "Warning" },
#define ERRDEF(num, offset, str) { num, str },
#define ERROR_END { 0, NULL } };
#elif !defined(ERROR_ENUM_DEFINED)
#define ERROR_START \
typedef enum svn_errno_t { \
WARNING = OS_START_USERERR + 1,
#define ERRDEF(num, offset, str) /** str */ num = offset,
#define ERROR_END ERR_LAST } svn_errno_t;
#define ERROR_ENUM_DEFINED
ERROR_START
ERRDEF(ERR_BAD_BAD,
ERR_BAD_CATEGORY_START + 0,
"Bad error")
ERRDEF(ERR_BAD_FILENAME,
ERR_BAD_CATEGORY_START + 1,
"Bogus filename")
ERROR_END
(复制自SubaseStase]
< P>因为C++不允许从Enm值自动转换为枚举名称或类似的名称,所以需要一个函数来完成。由于您的O/S中没有以某种方式定义错误代码,因此您需要自己翻译它 一种方法是大开关语句。另一种是表搜索或表查找。什么是最好的取决于错误代码集 表搜索可以通过以下方式定义:struct {
int value;
const char* name;
} error_codes[] = {
{ ERR_OK, "ERR_OK" },
{ ERR_RT_OUT_OF_MEMORY, "ERR_RT_OUT_OF_MEMORY" },
{ 0, 0 }
};
const char* err2msg(int code)
{
for (int i = 0; error_codes[i].name; ++i)
if (error_codes[i].value == code)
return error_codes[i].name;
return "unknown";
}
我倾向于避免切换,因为它通常是一大块代码。我更喜欢沿着以下行进行表格查找:
In btree.h:
enum btreeErrors {
ZZZ_ERR_MIN = -1,
OKAY,
NO_MEM,
DUPLICATE_KEY,
NO_SUCH_KEY,
ZZZ_ERR_MAX };
In btree.c:
static const char *btreeErrText[] = {
"Okay",
"Ran out of memory",
"Tried to insert duplicate key",
"No key found",
"Coding error - invalid error code, find and destroy developer!"
};
const char *btreeGetErrText (enum btreeErrors err) {
if ((err <= ZZZ_ERR_MIN) || (err >= ZZZ_ERR_MAX))
err = ZZZ_ERR_MAX;
return btreeErrText[err];
}
btree.h中的:
枚举btreeErrors{
ZZZ_ERR_MIN=-1,
可以
没有!,
重复_键,
没有这样的钥匙,
ZZZ_ERR_MAX};
在btree.c中:
静态常量字符*BTreerText[]={
“好的”,
“内存不足”,
“试图插入重复密钥”,
“找不到密钥”,
编码错误-错误代码无效,请查找并销毁开发人员
};
常量字符*btreeGetErrText(枚举btreeErrors){
如果((err=ZZZ_err_MAX))
err=ZZZ_err_MAX;
返回btreeErrText[err];
}
这通常并不重要,因为错误应该是例外而不是规则,但是表查找通常比运行大开关语句更快(除非它们得到了大量优化)。就我而言,错误代码只是枚举的一个子集。因为C++中没有漂亮的枚举(这使得日志很难解析),所以错误代码就不那么容易了。 对于错误代码,解决方案非常简单:
class ErrorCode
{
public:
ErrorCode(): message(0) {}
explicit ErrorCode(char const* m): message(m) {}
char const* c_str() const { return message; }
std::string toString() const
{
return message ? std::string(message) : std::string();
}
private:
char const* message;
};
std::ostream& operator<<(std::ostream& out, ErrorCode const& ec)
{
return out << ec.c_str();
}
类似于,但更一般化一点:
typedef std::map<int, const char*> error_code_tbl_t;
typedef error_code_tbl_t::value_type error_code_entry_t;
const error_code_entry_t error_code_tbl_[] = {
{ ERR_OK , "ERR_OK" },
{ ERR_RT_OUT_OF_MEMORY, "ERR_RT_OUT_OF_MEMORY" },
// ...
};
const error_code_tbl_t error_code_tbl( begin(error_code_tbl_)
, end (error_code_tbl_) );
const char* err2msg(int code)
{
const error_code_tbl_t::const_iterator it = error_code_tbl.find(code);
if(it == error_code_tbl.end())
return "unknown";
return it->second;
}
typedef std::map error\u code\u tbl\t;
typedef error_code_tbl_t::value_type error_code_entry_t;
常量错误\u代码\u条目\u t错误\u代码\u tbl\u[]={
{ERR_OK,“ERR_OK”},
{ERR_RT_OUT_MEMORY,“ERR_RT_OUT_MEMORY”},
// ...
};
常量错误代码错误代码(begin)(错误代码)
,结束(错误代码待定);
常量字符*err2msg(整数代码)
{
const error\u code\u tbl\u t::const\u迭代器it=error\u code\u tbl.find(code);
if(it==error\u code\u tbl.end())
返回“未知”;
返回->秒;
}
(可以找到那些
begin()
和end()
函数。)我想要一种方法,在一个且只有一个地方声明错误代码(int)和字符串描述(任何字符串),上面的示例都不允许这样做(ERR_OK必须在某个地方声明,然后“ERR_OK”映射到其他地方)
因此,我声明了一个简单的类,它同时存储int和string,并为int->string转换维护一个静态映射。我还添加了一个“自动转换为”int函数:
class Error
{
public:
Error( int _value, const std::string& _str )
{
value = _value;
message = _str;
#ifdef _DEBUG
ErrorMap::iterator found = GetErrorMap().find( value );
if ( found != GetErrorMap().end() )
assert( found->second == message );
#endif
GetErrorMap()[value] = message;
}
// auto-cast Error to integer error code
operator int() { return value; }
private:
int value;
std::string message;
typedef std::map<int,std::string> ErrorMap;
static ErrorMap& GetErrorMap()
{
static ErrorMap errMap;
return errMap;
}
public:
static std::string GetErrorString( int value )
{
ErrorMap::iterator found = GetErrorMap().find( value );
if ( found == GetErrorMap().end() )
{
assert( false );
return "";
}
else
{
return found->second;
}
}
};
然后,任何返回int的函数都可以返回1
return ERROR_SYSTEM_NOT_INITIALIZED;
而且,调用时,库的客户端程序将得到“系统尚未初始化”
Error::GetErrorString( 1 );
我看到的唯一限制是,如果many.cpp包含声明静态错误对象的.h文件,则会多次创建静态错误对象(这就是为什么我在构造函数中执行_调试测试以检查映射的一致性)。如果您没有数千个错误代码,那么这应该是一个问题(可能有解决方法…)
Jean您的错误代码来自哪里?自定义还是系统?什么错误代码。在我的项目中,我从函数返回错误代码,如
ERR\u OK
,ERR\u RT\u OUT\u OF\u MEMORY
,ERR\u OBJECT\u NOT\u FOUND
等。我想将这些代码转换成字符串,但这些错误代码是您自己定义的还是来自其他地方?@ereOn我自己定义的:)如果您的错误代码是连续的,那么您可以使用字符串数组而不是结构数组。因此,您可以通过索引访问错误字符串。保留错误数以检查数组边界。所以不需要每次都在数组中循环。@gtikok:当然,真正的问题是为什么还要麻烦代码呢?我自己会说,错误字符串的地址作为标识符是足够的,所有形式的查找都是多余的。@Matthieu M。这样您可以更好地控制代码值。我不会依赖字符串地址。@harper:这是一个不错的解决方案,但有一个输入错误。您编写了error\u code
并定义了error\u code
@ereOn:如果您确实需要代码值(用于文档?),那么它当然有点不同(尽管指针仍然足够,但它只需要指向结构代码/消息)。然而,need
并不十分清楚,MSVC的编译消息中有错误代码,而Clang没有,但我发现Clang的诊断更好。它是用于日志记录的。例如,我还可以考虑一个字符串数组const char*errorMessages[ERR\u CORE\u LAST]
,然后:大量errorMessages[ERR\u RT\u OUT\u内存]=“运行时-内存不足”代码>--那么什么更好呢?你觉得阵列版本怎么样?阵列还可以。Th
return ERROR_SYSTEM_NOT_INITIALIZED;
Error::GetErrorString( 1 );