将错误代码转换为要显示的字符串 < 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 );