【问题标题】:void* casting in 2 ways: (Sometype_t*)(*ptr) vs. *((Sometype_t**)ptr), why does only the second work?void* 以两种方式强制转换:(Sometype_t*)(*ptr) 与 *((Sometype_t**)ptr),为什么只有第二种有效?
【发布时间】:2016-02-08 11:33:00
【问题描述】:

这可能是一个愚蠢的问题,但我一直在努力寻找解释(主要是因为我无法提出这个问题)。

所以我有一个void* pointer,当传递给函数时它实际上是一个void** double-pointer,我们称之为ptr

#include <stdlib.h>

void aFunction(void* ptr);

typedef struct Type_ {
    char something[10];
} Type_t;

int main() {
    void* s = malloc(sizeof (Type_t));
    void** d = &s;

    aFunction(d);

    return (0);
}

void aFunction(void* ptr) {
    //Option 1
    Type_t* o1 = (Type_t*) (*ptr);

    //Option 2
    Type_t* o2 = *((Type_t**) ptr);
}

选项 1 不起作用(它没有编译,NetBeans 或者更确切地说是 GNU 编译器告诉我这不是您使用 void 指针的方式)但选项 2 可以。

我不明白为什么第一个不起作用。在我看来,它应该如下 1. 使用*ptr 我们得到void* 2. void* 被强制转换为Type_t*

有人能解释一下这里的技术性吗?

编辑:

对不起,我先写错了这个问题。我的实际问题只存在于函数的参数为​​void*且传入void**时。

【问题讨论】:

  • 这是 C 还是 C++?您已经双重标记,但规则不同。对于 C,您根本不需要也不应该使用任何演员表。对于 C++,推荐的做法是使用不同的强制转换语法来保护自己免受意外的无意义强制转换。请摆脱这些标签之一。什么特别不适用于您第一次尝试的方法?
  • “但这不起作用” - 您没有显示真实的完整代码。当我尝试使用演员表对该行进行最简单的解释时,即使在 C++ 中也一切正常:int main() { void** ptr = nullptr; using Type_t = int; Type_t* a = (Type_t*) (*ptr); } 它编译和运行时没有未定义的行为、崩溃或任何其他不好的事情。故事的寓意:“不起作用”不是可接受的问题描述。
  • 再想一想,取消引用 nullptr 当然是未定义的行为(那些讨厌的双指针会在我的大脑中导致无穷无尽的解析问题)。也许这就是你的意思?
  • @ChristianHackl 抱歉,我创建了一个示例。另外我错误地使用了推荐的标签C++,它只是C。
  • @hvd 我解决了最初的问题,希望现在更容易理解。

标签: c pointers casting


【解决方案1】:

取最先生效的版本:

void aFunction(void** ptr) {
    //Option 1
    Type_t* o1 = (Type_t*) (*ptr);

    //Option 2
    Type_t* o2 = *((Type_t**) ptr);
}

请注意,我已将 ptr 更改为 void**

选项1读取ptr指向的值。然后将该值转换为Type_t*。相当于Type_t* o1 = *ptr;,如果可能的话应该写成这种形式。

选项 2 告诉编译器 ptr 并不真正指向 void*,而是指向 Type_t*,然后读取该值。

现在把它改成不起作用的,把ptr改回void*

选项 1 无法读取ptr 指向的值,因为它不知道它正在处理什么样的值。由于它无法读取值,因此无法将其转换为Type_t*

选项 2 告诉编译器 ptr 指向 Type_t*,然后读取该值。

这就是为什么选项 1 在这种情况下不起作用的原因。

但是,请注意,告诉编译器 ptr 指向 Type_t* 而实际上它并不指向 Type_t* 可能会导致各种难以调试的问题,因为当您调用函数时作为

void* p = 0;
aFunction(&p);

编译器有时可能会看到“哦,我不知道ptr 指向什么,但程序员告诉我它指向Type_t*,所以我知道它不能指向p 。”并且可以基于该假设进行优化,例如不初始化p,因为它已经确定p 没有被访问。或者至少不是以编译器允许的方式。如果这是调用aFunction 的方式,那么访问p 的值的正确方法是Type_t* o1 = *((void**)ptr);:这告诉编译器ptr 确实指向void*,它确实如此。然后它取消引用ptr,读取void*,并将void* 转换为Type_t*

另一方面,如果ptr 确实指向Type_t*,例如在调用它时

Type_t** p = 0;
aFunction(&p);

然后告诉编译器ptr 确实指向Type_t* 是完全正确的。

您应该采用哪种方法取决于您如何调用aFunction

【讨论】:

    猜你喜欢
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 2020-09-07
    • 1970-01-01
    • 1970-01-01
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多