【问题标题】:What is a proper way to return NOT NULL pointer返回 NOT NULL 指针的正确方法是什么
【发布时间】:2013-01-23 10:49:23
【问题描述】:

我在我的 C++ 程序中使用了一个外部 C 库,并且该库使用了一个回调函数,该函数必须返回 void*。库检查返回值是否不为 NULL,表示成功。

那么告诉它一切都很好的最好方法是什么?

我用:

return reinterpret_cast<void*>(1);

但它看起来很丑......

编辑:感谢您的回复,我会继续这样做:

static int success;
return &success;

【问题讨论】:

  • 返回值是否有(其他)语义?
  • 我很好奇。图书馆是什么?
  • 什么是丑陋的?很美丽。它有 对和 () 对。还有单词return and reinterpret,它重复了我最喜欢的字母R。你还想要什么?
  • @GrahamBorland 它是 Mongoose 网络服务器,有时它使用返回的指针,但在简单的情况下只是检查它是否不为 NULL。
  • 如果你确定不用,那你的方式也可以

标签: c++ pointers


【解决方案1】:
static int dummy;
return &dummy;

严格来说,static 可能不是必需的,但返回一个指向超出范围的本地的指针感觉有点粗俗。

编辑:注意@sharptooth 的评论。严格来说,static 必需的。

【讨论】:

  • 如果没有static,你会得到一个悬空指针并且使用(甚至复制)这样的指针是UB。
  • @sharptooth:我原以为复制指针会很好,只要它构造正确(即,在某些时候有效)。请注意,我不是不同意,只是感到惊讶。
  • 是的,这是一个常见的误解stackoverflow.com/a/1866543/57428,它只适用于大多数架构,但它是 UB。
  • @MarceloCantos: static void* success = reinterpret_cast&lt;void*&gt;(&amp;success); 允许return success; 之后:D
【解决方案2】:

使用reinterpret_cast 尽可能干净。问题是从int 文字中制作此类指针会产生未定义的行为——标准禁止使用非空指针且未指向正确分配的对象。符合标准的方法是有一些变量(也许文件范围变量是最方便的)并返回其地址。

【讨论】:

  • 这是不正确的。 reinterpret_cast&lt;void*&gt;(1) 是定义明确的代码,用于根据指针和整数之间的实现定义映射创建实现定义的指针值。 (参见 C++ 标准子句 [expr.reinterpret.cast]/5)
  • @Bart van Ingen Schenau:很好,但是如果它产生一个无效的指针,你会得到 UB。
  • @BartvanIngenSchenau:如果不出意外,UB 是调用者将指针值与空指针进行比较。我不确定返回一个无效的指针值是否算作“使用”它([basic.stc.dynamic.deallocation]/4),但是将它与 null 比较可以。我也不清楚void*int 之间的实现定义映射是否需要包含与int每个 值对应的指针值,或者是否允许实现定义 1 根本没有值,并且演员表本身将陷入陷阱或其他任何东西。
  • @SteveJessop:我遇到的问题是实现定义(从 C++11 开始)reinterpret_cast&lt;void*&gt;(1) 的结果是否会导致 无效的指针值。据我所知,在 C++11 之前,这是没有指定的(我假设是整数和指针之间映射的一部分)。
  • @BartvanIngenSchenau:IIRC C 标准至少定义了有效指针是什么((void *)1 未列出)。我想知道为什么它没有像您声称的那样复制'n'粘贴到 C++ 标准中(我没有时间检查它)。
【解决方案3】:

我可能会写这样的东西:

return const_cast<void*>(""); // non-null pointer, referand doesn't matter

也许回调函数有一个指针输入保证不为空。如果是这样,那么您可以将其退回。

reinterpret_cast&lt;void*&gt;(1)应该看起来很丑,因为它不能保证工作。大多数架构不介意你这样做,但是

  • 该标准实际上并不能保证您可以使用不是任何对象的地址的指针值(或空指针,或数组的末端)。
  • 标准不保证reinterpret_cast&lt;void*&gt;(1) 不是空指针,这是实现定义的。

我怀疑是否真的存在您的函数意外返回 null 的实现,但 允许 存在。想象一个假设的实现,其中 CPU 自己的寻址是 4 位而不是 8 位。当然,实现者仍然会选择CHAR_BIT == 8,并且C++ 中的所有指针都是8 位对齐的。然后,通过保持位模式不变,实现可以合法且相当合理地从指针映射到整数,并通过将最后一位归零来从整数映射到指针。或者,它可以右移和左移 1 位。该标准要求指针->整数->指针恢复原始值,但不要求整数->指针->整数。

【讨论】:

  • 试过了:错误:从‘const void*’到‘void*’的无效转换
  • @user286215:哎呀。你可以 const_cast 它。但是,只要调用者使用返回值,您所需要的只是一个仍然存在的对象。所以找一个非 const 的偏好,而不是像 "" 和 cast 这样的 const 。
  • const_cast&lt;void*&gt;("") 都不能保证工作,因为"" 是一个常量字符串。或者,我错了吗?
  • @BЈовић 之前还有其他建议。现在好了。
  • @BЈовић:没有明确禁止将指向非 const 的指针指向定义为 const 的对象。我怀疑同样的问题也适用于 C++,正如我最近询问的 C (stackoverflow.com/questions/14437699)。我也怀疑答案是一样的,虽然没有明确说你可以做到,但有文本禁止修改(但不读取)这些对象,如果你不能有效地获得对它们的非常量引用,这些对象将是多余的首先。但是我还没有仔细研究 C++ 标准的细节。我很确定这样做的目的是您可以。
【解决方案4】:

怎么样

return this;

作为返回保证为非 NULL 的有效指针的简单方法?

【讨论】:

  • 或者如果函数是独立函数而不是成员函数,函数本身的地址。
  • @JoachimPileborg 我认为不允许从函数指针转换为数据指针?
  • @R.MartinhoFernandes 我相信你是对的,但如果所有 OP 想要的是一个有效的指针,那么它应该没关系。这完全取决于库使用指针的目的。
  • 很遗憾,它不是班级成员。 @JoachimPileborg,漂亮的解决方案,但也需要重新解释转换)
【解决方案5】:

如果是我,我会使用:

return (void*)1;

简单漂亮。

我更喜欢值 1(正如您在问题中使用的)而不是任何其他值,因为其他值可以以某种方式解释(这不好)。如果您只想返回一个非零值(非空指针),则最好使用一个无法从中提取任何特殊内容的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2012-12-29
    • 1970-01-01
    • 1970-01-01
    • 2016-09-25
    • 1970-01-01
    • 2011-08-24
    相关资源
    最近更新 更多