代码之家  ›  专栏  ›  技术社区  ›  Karl von Moor

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

c++
  •  4
  • Karl von Moor  · 技术社区  · 14 年前

    C++中有没有一种常见的方法将错误代码翻译成字符串来显示它?

    我在某个地方看到了 err2msg 功能,大开关,但这真的是最好的方法吗?

    7 回复  |  直到 14 年前
        1
  •  12
  •   harper    8 年前

    由于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";
    }
    
        2
  •  3
  •   user001    14 年前

    在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

        3
  •  3
  •   Community Navdeep Singh    7 年前

    类似 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 .)

        4
  •  2
  •   Matthieu M.    14 年前

    就我而言,错误代码只是枚举的一个子集。因为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");
    
        5
  •  2
  •   frast    14 年前

    您应该记住,这些错误字符串可能不是您想要向用户显示的。为了便于翻译,用户的混乱应该保存在资源中。

    错误代码的字符串用于日志或诊断,不需要翻译。

    可以使用此技巧在parralell中定义错误代码和字符串:

    #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
    

    (从subversion源复制)

        6
  •  1
  •   paxdiablo    14 年前

    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];
        }
    

    这并不重要,因为错误应该是异常而不是规则,但是表查找通常比运行大开关语句快(除非它们得到了极大的优化)。

        7
  •  0
  •   jpo38    10 年前

    我想要一种方法,让错误代码(int)和字符串描述(任何字符串)声明在一个地方,只有一个单一的地方,上面的例子都不允许这样(ERR_OK必须声明在某处,然后“ERR_OK”被映射到其他地方)。

    因此,我声明了一个简单的类,它同时存储int和string,并为int->字符串转换维护一个静态映射。我还添加了一个“auto cast to”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文件包含在many.cpp中,则会多次创建静态错误对象(这就是我在构造函数中执行调试测试以检查映射的一致性的原因)。如果你没有成千上万的错误代码,这应该是一个问题(可能有一个解决方法…)

    牛仔