【问题标题】:void pointer in function parameter函数参数中的空指针
【发布时间】:2015-09-06 10:26:23
【问题描述】:

考虑以下程序:

#include <iostream>
void f(void* a)
{
    std::cout<<"(void*)fun is called\n";
    std::cout<<*(int*)a<<'\n';
}
int main()
{
    int a=9;
    void* b=(int*)&a;
    f(b);
    return 0;
}

如果我像这样更改函数调用语句:

f(&amp;b);

它仍然可以正常编译并在运行时崩溃。为什么?是什么原因?我不应该得到编译时错误吗?因为调用函数的正确方法是 f(b)。正确的?另外,为什么允许将 NULL 传递给参数类型为 (void*) 的函数?

如果我遗漏了什么或理解不正确,请纠正我。

【问题讨论】:

  • 指针的指针仍然是指针,所以它被接受为 void*。
  • 你可能想通过a的地址来达到同样的效果:f(&amp;a);
  • @meet 虽然 EdHeals cmets 不是很好,但基本上他是对的。如果您不明白这是做什么的,请不要这样做。你甚至不需要任何指针。

标签: c++ pointers parameter-passing void-pointers


【解决方案1】:

它仍然可以正常编译并在运行时崩溃。为什么?是什么原因?

因为void* 是一种删除所有类型安全和类型检查的技术。

我不应该得到编译时错误吗?

通过使用void* 而不是正确的指针类型int*,您明确告诉编译器不要告诉您如果您使用了不正确的类型或以未定义的方式使用。 p>

因为调用函数的正确方法是 f(b)。对吧?

这就是你的函数声明内容不一致的地方。

    std::cout<<"(void*)fun is called\n";
    std::cout<<*(int*)a<<'\n';

上面的内容暗示应该传递一个指向int的指针:

void f(void* a)

这个声明暗示一些指针应该被传递,并且没有其他限制。

【讨论】:

    【解决方案2】:

    void*可以捕获任何类型的指针,void**也不例外

    【讨论】:

    • 为什么它在运行时崩溃?
    • @meet,您将b 的地址解释为int*,但b 本身是一个指针,而不是int
    【解决方案3】:

    好的。

    根据要求。

    不要使用 void 指针,除非你想不出任何其他方法来解决它。

    然后上床再想一想。

    Void 指针使程序员能够忘记类型。这意味着编译可以放弃简单的检查。这在我看来也意味着程序员失去了剧情。

    如果你愿意,请给我投反对票。

    使用类型可以让编译器为您检查内容。例如。事物是如何相关的。如何处理该对象。

    但是使用 void 指针,您非常依赖自己。祝你好运

    【讨论】:

      【解决方案4】:

      您不会收到编译时错误,因为f(&amp;b) 调用f 并将b 的地址作为参数传递,然后将其转换为void*。您会收到运行时错误,因为那时您正试图将指向整数的指针转换为整数。 但是,是的,正如其他人所说,这样做非常糟糕。

      【讨论】:

        【解决方案5】:

        第一

        您可以将void* 指向void**。您的代码是显示void* 指针有多危险的众多示例之一。

        第二

        你应该用于类型转换:

        void* b = static_cast&lt;int*&gt;(&amp;a);

        而不是您使用的 c 样式转换:

        void*b = (int*)&a;
        

        【讨论】:

          【解决方案6】:

          如果我像这样更改函数调用语句: f(&b); 它仍然可以正常编译并在运行时崩溃。为什么?

          您的函数f(void*) 将接受指向任何类型的指针,而无需抱怨。任何指针都会悄悄地转换为 void 指针。指向指针的指针仍然是指针。所以你的第二种情况确实编译得很好。然后它崩溃了。也许吧。

          在第一种情况下,您将指向 int 的指针转换为指向 void 的指针,再转换回指向 int 的指针。通过void*(以及通过char*)的那些往返转换必须有效。在第二种情况下,您从void** 转换为void* 再转换为int*。现在您正在调用未定义的行为。什么都行。在我的计算机上,我的编译器上,你的代码运行得很好。它打印垃圾。我很确定您的代码不会擦除我的硬盘,但它可以。任何事情都伴随着未定义的行为。不要调用未定义的行为。

          支持void* 的原因是历史性的。有很多使用 void 指针的旧 C 和 C++ 代码。编写使用 void 指针的新 C++ 代码的唯一原因是您需要与使用 void 指针的旧函数之一进行交互。

          【讨论】:

            【解决方案7】:

            我发现自己在这里是因为我正在做一项要求相同功能的家庭作业。结合每条评论后,这就是我想出的。

            // A function that accepts a void pointer
            void f(void* a)
            {
                std::cout<<"(void*)fun is called\n";
                std::cout<< "value for a: " << *(int*)a << '\n';
            }
            
            
            int main() {
                int a = 9;
                void* c = static_cast<int*>(&a);
            
                int b = 3;
                f(&b);
                f(c);
            }
            

            【讨论】:

            • 编译器在运行时永远不会崩溃 :)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-02-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多