将错误代码转换为要显示的字符串

时间:2010-10-20 06:38:56

标签: c++

C ++中是否有通用的方法将错误代码转换为字符串以显示它?

我在某个地方看到了一个err2msg函数,有一个很大的开关,但这真的是最好的方法吗?

7 个答案:

答案 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测试以检查映射的一致性)。如果您没有数千个错误代码,那么它应该是一个问题(并且可能有解决方法......)