我正在为realloc
写一个包装器。对于返回值,我使用以下代码:
typedef enum { SALLOC_OK, SALLOC_OVERFLOW, SALLOC_ALLOCFAIL, ... } salloc_rc;
这在这样的函数中使用:
salloc_rc salloc(<args>) {
if(blabla) return SALLOC_OVERFLOW;
if(blabla) return SALLOC_ALLOCFAIL;
/* More error codes */
return SALLOC_OK;
}
这当然不是完整的代码,但是足以演示我想要的内容。到目前为止,一切都很好。我可以这样检查返回值:
if(salloc(a,b) != SALLOC_OK) // Handle error
或者,如果我想更精确一点:
if(salloc(a,b) == SALLOC_OVERFLOW) // Handle overflow
但是,我希望它与检查错误的常规方法兼容。我希望能够使用:
if(!salloc(a,b)) // Handle error
和
if(salloc(a,b) { /* Do stuff */ }
else { /* Handle error */ }
这里的问题是0为假,其他所有为真。我想做的事情似乎是不可能的,但是围绕它可能有一些我错过的方法。到目前为止,我发现的唯一解决方案是为该函数提供一个额外的参数,并带有一个指向可以存储错误代码的位置的指针,但是我想尽可能避免这种情况。
TL; DR
如何使函数<type> foo()
能够根据出了什么问题返回不同的错误消息,同时仍保持以“传统”方式检查错误的可能性,例如
if (!foo()) exit(EXIT_FAILURE);
答案 0 :(得分:3)
如果您写
if (! salloc(a,b)) handleError();
那是完全错误的。严重的错误。但是如果你写
if (salloc(a, b)) handleError();
然后,作为您的代码阅读者,我不知道该声明是否正确,这迫使我阅读文档。因此,正确的方法是:
salloc_rc returnCode = salloc(a, b);
if (returnCode != SALLOC_OK) handleError();
这很干净,它可以告诉读者确切的情况,它使您有机会在您检查返回代码的地方设置一个断点。赢了。不要担心一些额外的击键。使您的代码可读。而且,如果您被告知使“代码检查错误的常用方法”难以阅读,那么请不要使用“代码检查错误的常用方法”。
请注意,在许多其他现代语言(Java,Swift)中,不能将枚举用作if语句中的条件或用作!的参数。 (不)。该死,我只是将Java称为“更现代的语言”:-(
答案 1 :(得分:3)
如果只需要一个成功代码和多个错误代码,则有多种选择。
没有一个是自然的/惯用的,因此就好像事情正好相反:
使用一些辅助空间来获取其他信息:
使用反向逻辑,这意味着只有false才是成功。
这提醒我们使用诸如strcmp()
之类的常规比较功能来检查相等性。
将某些返回值范围专用于错误:
使用负数表示错误。令人高兴的是,您拥有成功的所有非负面因素。
COM does that extensively与their HRESULT
。与许多Linux系统调用一样。
浮点数通常具有许多NaN值。可以在其中放置细节,有些架构甚至可以保证以最小的代码传播。不幸的是,这种方法很少使用,花费很少,因此没有遵循新的说明。
还有一些不太方便的示例。
我的建议是,如果可以的话,将其存储在被操纵的对象中,然后存储errno
,然后是取反的逻辑,最后是COM约定。
答案 2 :(得分:1)
通常情况恰好相反。
if(salloc(a,b)) // Handle error
if(USB_Transmit(a,b)) // Handle error
这是一个非常简单的逻辑-如果函数返回的非零值-则表示存在错误。
现实生活中的例子: STM库: / *遵循USB设备状态* /
typedef enum {
USBD_OK = 0,
USBD_BUSY,
USBD_FAIL,
}USBD_StatusTypeDef;
#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command
#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing
#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled
#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error
#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation
#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found
#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported
#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter
#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state
#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length
#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags
#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data
#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size
#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out
#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer
#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation
#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address
#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy
#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded.
#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation
其中NRF_ERROR_BASE_NUM通常为0