如何避免枚举值的冲突?

How to avoid collision of enumerated values?

提问人:Nick 提问时间:9/12/2014 最后编辑:5gon12ederNick 更新时间:1/14/2015 访问量:169

问:

我正在构建一个前端库。后端会生成许多枚举的错误代码:

enum backerr {BACK_ERR1, BACK_ERR2, BACK_ERR3};

我的前端会产生一些额外的错误代码:

enum fronterr {FRONT_ERR1, FRONT_ERR2, FRONT_ERR3};

为方便起见,我希望有一个错误代码返回函数,该函数将根据发生的错误返回前端或后端错误。

考虑到我们无法知道后端的值,有没有办法在不冲突两个错误代码的值的情况下发生这种情况?

c

评论

1赞 David Grayson 9/12/2014
我以前处理过这个问题。我认为前端必须对后端的错误代码有足够的了解,确保前端错误代码是后端代码的超集。您可以尝试为后端保留前 1000 个号码,并将其余号码用于前端。
0赞 M.M 9/12/2014
另一个选项是让错误代码具有指示它来自哪个枚举的部分,以及指示枚举值的其余部分
0赞 Jonathan Leffler 9/12/2014
到目前为止,最简单的机制是定义所有后端错误都是负数,所有前端错误都是正数,反之亦然,并保留 0 表示“不是错误”。考虑如何处理系统错误(1 到大约 150 范围内的值可以出现在前端或后端);您可能希望为 O/S 保留至少 1..200,并像以前一样使用正值和负值来区分前端和后端。我开发的软件使用100到121之间的错误号来表示自己的错误;只去50岁就好了,但给了无尽的悲伤。errnoerrno
0赞 Nick 9/12/2014
问题是,我无法通过后端访问。我的前端是一个单独的项目。后端的所有规范都说错误代码应该是非零的,所以我想它可能因实现而异。我可能要求太多了。
0赞 Jonathan Leffler 9/12/2014
如果无法控制后端,则无法控制这些枚举。你必须设计一种机制,可靠地将错误源标记为前端或后端,并接受你最终可能会得到相同的错误号,这意味着两个不同的问题,这取决于源是前端还是后端。另一个问题后来出现了,当生态系统发展时,前端变成了中间的一部分,并且有新的前端代码,等等。您可能需要一个标记系统,该系统不仅可以处理前端/后端二分法。

答:

2赞 paxdiablo 1/13/2015 #1

如果您不知道后端可能会生成什么,那么,不,没有办法可靠地选择您自己的错误代码,以免它们发生冲突。

所以你有几个选择(至少)。

如果后端以某种方式发布错误范围(例如在头文件中),则第一个很有用。老实说,它应该这样做,因为程序没有其他方法可以区分不同的错误代码和/或类型。

如果它们发布,那么发现最高代码并选择自己的代码以留出足够的空间来扩展后端是一件简单的事情。例如,如果后端使用 ,则从 开始。任何系统突然报告错误数量是以前版本十倍的可能性很小。1..1001000

第二种方式是,如果你想要真正的分离,冲突的可能性为零。

没有什么可以阻止您返回类似于以下内容的结构:

struct sFrontError {
    enum fronterr errorCode;
    enum backerr  backendCode;
};

并用它来弥补你的错误。然后,前端的枚举将变为:

enum fronterr {FRONT_OK, FRONT_BACK, FRONT_ERR1, FRONT_ERR2, FRONT_ERR3};

您可以按如下方式对其进行评估:

  • 如果是,则没有错误。errorCodeFRONT_OK
  • 如果是 ,则错误来自后端,您可以在 中找到其代码。errorCodeFRONT_BACKbackendCode
  • 否则,这是一个前端错误,并且代码完全指定了它。errorCode

评论

0赞 M.M 1/13/2015
类似的选项是使用 HRESULT 等方案。
0赞 5gon12eder 1/14/2015
很好的附加方法。你有什么理由声明和作为和不是作为各自的s?我知道它在 C 中是允许的,但发现它有点令人困惑。另一个灵感来源可能是C++system_error标头,它试图以与你展示的解决方案类似的方式解决类似的问题(除了它还需要支持多个后端)。errorCodebackendCodeintenum
1赞 5gon12eder 1/13/2015 #2

如果后端公开了其错误代码的详尽列表,您可以轻松地创建它们的真实超集,而您自己的前端错误代码是一个不相交的子集。

/* in backend.h */

enum backend_error
{
  BACK_ERR_1,
  BACK_ERR_2,
  BACK_ERR_3,
};
/* in frontend.h */

#include <backend.h>

enum frontend_error
{
  FRONT_ERR_1 = BACK_ERR_1,
  FRONT_ERR_2 = BACK_ERR_2,
  FRONT_ERR_3 = BACK_ERR_3,
  FRONT_ERR_4,
  FRONT_ERR_5,
};

此方法不会强制你对后端错误代码的值做出任何假设,但如果后端的未来版本定义了其他错误代码,你可能会被灌管。另一个缺点是,您的头文件是后端的头文件,因此您正在污染命名空间。#include

如果您的用户从不直接调用后端,也就是说,您正在为所有后端功能提供抽象,则可以完全定义自己的错误代码,并拥有一个将后端错误代码映射到您自己的函数。由于此函数不需要作为标识函数,因此即使面对后端的未来更改,您也始终可以使此函数工作。它也可以在你自己的实现文件中实现,以使后端命名空间远离你的用户图片。