在c++中将错误代码映射为字符串

Mapping error codes to string in C++

本文关键字:映射 字符串 错误代码 c++      更新时间:2023-10-16

将错误代码从枚举映射到字符串的更有效的方法是什么?(在c++中)

例如,现在我这样做:

std::string ErrorCodeToString(enum errorCode)
{
   switch (errorCode)
   {
      case ERROR_ONE:   return "ERROR_ONE";
      case ERROR_TWO:   return "ERROR_TWO";
      ...
      default:
         break;
   }
   return "UNKNOWN";
}

如果我这样做会更有效率吗?:

#define ToStr( name ) # name;
std::string MapError(enum errorCode)
{
   switch (errorCode)
   {
      case ERROR_ONE:   return ToStr(ERROR_ONE);
      case ERROR_TWO:   return ToStr(ERROR_TWO);
      ...
      default:
         break;
   }
   return "UNKNOWN";
}
也许有人对此有任何建议或想法?谢谢。

如果你打算使用宏,为什么不从头开始:

std::string MapError(enum errorCode)
{
    #define MAP_ERROR_CODE(code) case code: return #code ;
    switch (errorCode)
    {
       MAP_ERROR_CODE(ERROR_ONE)
       MAP_ERROR_CODE(ERROR_TWO)
       ...
    }
    #undef MAP_ERROR_CODE
    return "UNKNOWN";
}

我想要一种方法,让错误码(int)和字符串描述(任何字符串)只能在一个地方声明,而上面的例子都不允许。

因此,我声明了一个简单的类来存储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;
        }
    }
};

然后,只需如下声明错误代码:

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;

并且,库的客户端程序在调用

时会得到"System is not initialized yet"
Error::GetErrorString( 1 );

或:

Error::GetErrorString( ERROR_SYSTEM_NOT_INITIALIZED );

我看到的唯一限制是,如果声明它们的.h文件被许多.cpp包含,则静态错误对象会被创建多次(这就是为什么我在构造函数中进行_DEBUG测试以检查映射的一致性)。如果你没有成千上万的错误代码,这应该不是一个问题(可能有一个解决方案…)

enum errors {
    error_zero,
    error_one,
    error_two
};
namespace {
const char *error_names[] = {
    "Error one",
    "Error two",
    "Error three"
};
}
std::string map_error(errors err) {
    return error_names[err];
}

您建议的替代方法并不更有效,但您可以通过两种方式改进:

  1. 显然在errorCode枚举和这个函数之间存在重复。
  2. 在你的函数中也有一些重复,因为枚举值与字符串给出的名称相同。

你可以用一点预处理魔法来解决这两个问题:

// This is your definition of available error codes
#define ERROR_CODES 
  ERROR_CODE(ERROR_ONE) 
  ERROR_CODE(ERROR_TWO) 
  ERROR_CODE(ERROR_THREE)
// Define ERROR_CODE macro appropriately to get a nice enum definition
#define ERROR_CODE(a) ,a
enum ErrorCode {
  None,
  ERROR_CODES
};
#undef ERROR_CODE
// Define ERROR_CODE macro differently here to get the enum -> string mapping
std::string MapError(enum errorCode)
{
   #define ERROR_CODE(a) case a: return #a;
   switch (errorCode)
   {
      case None: return "None";
      ERROR_CODES
   }
}

不,在预处理器通过您的代码后,两者将完全相同。唯一的问题是第二种方法更不容易出现错别字。

我想说你已经实现了一个很好的解决方案。

我知道这是一个旧线程,但我确实喜欢Frerich Raabe的方法,并使其在VS中工作而没有错误:

#define ERROR_CODES 
    ERROR_CODE(NO_ERROR) 
    ERROR_CODE(ERROR_ONE) 
    ERROR_CODE(ERROR_TWO) 
    ERROR_CODE(ERROR_THREE) 
    ERROR_CODE(ERROR_FOUR)
#define ERROR_CODE(code) code,
typedef enum { ERROR_CODES } ErrorCodes;
#undef ERROR_CODE
const char *MapError(const int errorCode)
{
#define ERROR_CODE(code) case code: return #code;   
    switch (errorCode)
    {
        ERROR_CODES
    default: return "UNKNOWN ERROR";
    };
#undef ERROR_CODE
}