【问题标题】:Is it possible to return different "false" in C?是否可以在 C 中返回不同的“false”?
【发布时间】:2019-06-20 07:28:54
【问题描述】:

我正在为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

如何使函数&lt;type&gt; foo() 能够根据出现的问题返回不同的错误消息,同时仍然保持以“传统”方式检查错误的可能性,例如

if (!foo()) exit(EXIT_FAILURE);

【问题讨论】:

  • 我更喜欢if(salloc(a,b) != SALLOC_OK)。它更明确,并使您的意图更清晰。如果不让事情变得比这更复杂、更不清晰,就没有办法让零意味着不止一件事。
  • 旁白:请注意,当realloc() 返回NULL 时,这本身并不意味着realloc() 失败。 realloc(ptr, 0) 是一个潜在的有效(非内存不足)响应。我明白你为什么想要realloc() 的包装器。
  • "可能在 C 中返回不同的 "false"?"当然 - 返回 0.0 或 -0.0,两者都是错误的,并且当支持 -0.0 时,两者都可以是 discerned - 但我认为 FP 答案在这里不是一个好方法。
  • @chux 不错,但我希望能够区分两个以上不同的错误。
  • @Broman ????抱怨,抱怨next 4 will be wanted,抱怨,抱怨,抱怨。

标签: c return return-value


【解决方案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

【讨论】:

  • 真的经常反其道而行之吗?至少它不适用于内存分配功能。失败时返回 NULL 指针。
  • @Broman 据我所知,他的实现不会只返回指针一些枚举。所以不是典型的内存分配函数
【解决方案2】:

如果你写

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】:

如果您只需要一个成功代码和多个错误代码,您有多种选择。
没有一个是自然/惯用的,因此就像事情相反:

  1. 为附加信息使用一些辅助空间:

    1. 使用errno 为感兴趣的人传输补充信息。
      标准库广泛地做到了这一点。

    2. 将特定错误存储在使用的对象中。 fgetc()feof()ferror() 一起使用。

    3. 为补充错误信息定义您自己的(线程本地)存储。

    4. 使用回调或额外的输出指针。

    5. 返回一个 struct 以及您需要的所有成员。

  2. 使用反转逻辑,意味着只有 false 才是成功。
    这让人想起使用像 strcmp() 这样的通用比较函数来检查相等性。

  3. 将一些返回值范围用于错误:

    1. 使用否定表示错误。好消息是您拥有所有成功的非负面因素。
      COM does that extensivelytheir HRESULT。许多 Linux 系统调用也是如此。

    2. 浮点数通常有很多 NaN 值。可以把细节放在那里,一些架构甚至保证用最少的代码传播那个。不幸的是,它很少使用,成本很低,因此没有遵循新的说明。

    还有其他不太方便的示例。

我的建议是尽可能将其存储在被操作对象中,然后是 errno,然后是否定逻辑,最后是 COM 约定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-30
    • 2010-10-24
    • 1970-01-01
    • 2013-05-15
    • 2011-08-10
    • 2019-08-21
    • 2016-12-23
    • 1970-01-01
    相关资源
    最近更新 更多