【问题标题】:Is it safe to pass a void pointer to function that accepts a non-void pointer?将 void 指针传递给接受非 void 指针的函数是否安全?
【发布时间】:2018-08-27 23:22:54
【问题描述】:

很简单,下面的代码安全/便携吗?

#include <stdio.h>
#include <stdlib.h>

int add(int *a, int *b)
{
  return *a + *b;
}

int main()
{
  int x = 2;
  int y = 3;

  void *ptr1 = &x;
  void *ptr2 = &y;

  fprintf(stdout, "%d + %d = %d\n", x, y, add(ptr1, ptr2));

  return EXIT_SUCCESS;
}

我已经用-Wall -Werror-Wextra 编译了这个并且没有收到任何警告;它似乎运行良好。

【问题讨论】:

    标签: c pointers void-pointers


    【解决方案1】:

    有两点需要考虑:

    1. C 允许从 void 指针隐式转换为任何其他对象指针类型。因此,传递这些参数在语法上是可以的。

    2. 被指向的实际对象的类型以及函数期望的指针类型必须满足strict aliasing 约束,否则您的程序将处于未定义的行为状态。

    你在这两点上都很好。所以你的程序非常好。

    【讨论】:

    • ...但这当然会关闭编译器的任何类型检查。
    • @PaulOgilvie - 考虑到编译器已经允许滑动多少......我个人不会称 C too 类型安全。尽管如此,它仍然是其强大力量的一部分。
    • 是的,C 就像电锯。你可以用它完成任何事情。它曾经是编写汇编程序的便捷方式,程序员知道编译器会生成什么。现在,它正在变成一种可怕的、半高级的语言,还有它的 UB 教条。
    • @EricPostpischil - 但这就是重点。允许对象指针转换。除非类型对齐,否则不会访问存储的值。无论如何,那是没有意义的。我去了另一个方向。
    • @StoryTeller:对齐和访问不是问题。兼容性是。 “对齐”和“访问”是 C 标准中具有不同含义的术语。
    【解决方案2】:

    这是安全的:

    C99

    指向 void 的指针可以转换为指向任何不完整或对象类型的指针或从指针转换。指向任何不完整或对象类型的指针可以转换为指向 void 的指针并再次返回;结果应与原始指针比较。

    但是你需要确保你原来的指针类型是正确的。

    【讨论】:

    • 指针可以转换的事实并不能保证生成的指针可以用于访问对象。需要 C 的其他规则,例如 C 2011 6.5 7 中的规则来证明这一点。此外,1999 年的标准已有近 20 年的历史,现已被撤销。
    【解决方案3】:

    没关系,但要靠牙齿的皮肤。

    您正在将int* 转换为void*,并且当指针按值传递到add 时,它又转换回int*

    例如,如果add 使用两个指向double 的指针,那么您的代码的行为将是未定义的。

    【讨论】:

      【解决方案4】:

      它是“安全的”,因为行为是明确定义的。当需要处理许多不同类型的数据时,将函数声明为接受void * 是正常的;例如memcpy.

      道德不安全。通过传递void *,您使编译器无法检查您传递的指针是否指向以您期望的形式和数量保存数据的内存。然后由您来执行此操作。

      在您的简单示例中,您可以看到对象实际上是int,一切都很好。

      然而,一般来说,当我们将void * 传递给一个函数时,我们还应该传递额外的信息来描述我们正在移交的内存,以便函数能够完成它的工作;如果我们有一个只处理一种类型的函数,我们会仔细研究那些让我们传递void * 值而不是那种类型的设计决策。

      出于理智考虑(并且,取决于编译器的性能),请考虑将您未写入的参数标记为const

      【讨论】:

        【解决方案5】:

        如果您知道转换为 void * 的指针始终指向一组已知类型(例如 char、short、int 等),您可以创建一个由联合和判别式组成的结构类型,并通过它,如有必要,重新投射。

        您可以将它作为指向未定义类型的指针传递,只是为了比 void * 更具体一点,这样就承担了一些责任。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-06-25
          • 1970-01-01
          • 2014-05-13
          • 1970-01-01
          • 1970-01-01
          • 2018-08-25
          • 2011-03-20
          • 1970-01-01
          相关资源
          最近更新 更多