C ++中是否有通用的方法将错误代码转换为字符串以显示它?
我在某个地方看到了一个err2msg
函数,有一个很大的开关,但这真的是最好的方法吗?
答案 0 :(得分:12)
由于C ++不允许从枚举值到枚举名称或类似名称的自动“转换”,因此您需要一个函数来执行此操作。由于您的错误代码未在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";
}
答案 1 :(得分:3)
在Windows中,您可以使用FormatMessage(...)
函数,使用GetLastError()
函数返回错误代码,也可以直接使用可疑区域。
请参阅以下链接以获取示例。
http://msdn.microsoft.com/en-us/library/ms679351(v=VS.85).aspx
http://msdn.microsoft.com/en-us/library/ms680582(v=VS.85).aspx
我希望这会对你有所帮助。
答案 2 :(得分:2)
这个大开关并没有那么糟糕。获取错误代码的字符串几乎总是不是性能关键。
您应该记住,这些错误字符串可能不是您要向用户显示的内容。用户的信息应保存在资源中以便于翻译。
错误代码的字符串用于日志或诊断,无需翻译。
您可以使用此技巧在parrallel中定义错误代码和字符串:
#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
(从颠覆来源复制)
答案 3 :(得分:2)
就我而言,错误代码只是枚举的一个子集。由于我们没有在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();
}
当然,您可以提供传统的==
,!=
,<
等...
这个想法是返回指向文本的指针而不是错误代码(虽然包装在类中以确保类型安全)。
用法:
// someErrors.h
extern ErrorCode const ErrorOutOfMemory;
// someErrors.cpp
ErrorCode const ErrorOutOfMemory = ErrorCode("OUT OF MEMORY");
答案 4 :(得分:2)
与harper's idea类似,但有点概括:
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;
}
(可以找到begin()
和end()
个here个函数。)
答案 5 :(得分:1)
我倾向于避免切换,因为它通常是一大段代码。我更喜欢表格查找:
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];
}
通常不重要,因为错误应该是异常而不是规则,但是表查找通常比运行大型switch语句更快(除非它们得到大量优化)。
答案 6 :(得分:0)
我想要一种方法让错误代码(int)和字符串描述(任何字符串)在一个且只有一个地方声明,并且上面的例子都不允许(ERR_OK必须在某处声明然后“ERR_OK”在其他地方映射到它。)
所以我声明了一个存储int和string的简单类,并为int-&gt;字符串转换维护静态映射。我还添加了一个“自动转换为”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;
}
}
};
然后,您只需将错误代码声明如下:
static Error ERROR_SUCCESS( 0, "The operation succeeded" );
static Error ERROR_SYSTEM_NOT_INITIALIZED( 1, "System is not initialised yet" );
static Error ERROR_INTERNAL( 2, "Internal error" );
static Error ERROR_NOT_IMPLEMENTED( 3, "Function not implemented yet" );
然后,任何返回int的函数都可以返回1
return ERROR_SYSTEM_NOT_INITIALIZED;
并且,在调用
时,您的库的客户端程序将获得“系统尚未初始化”Error::GetErrorString( 1 );
我看到的唯一限制是静态错误对象被多次创建,如果.h文件声明它们被许多.cpp包含(这就是为什么我在构造函数中进行_DEBUG测试以检查映射的一致性)。如果您没有数千个错误代码,那么它应该是一个问题(并且可能有解决方法......)
让