【问题标题】:What type of cast does *( char** ) achieve?*( char** ) 实现什么类型的演员表?
【发布时间】:2019-12-02 01:17:47
【问题描述】:

*( char** ) 完成什么类型​​的演员表?
它似乎用** 创建了一个指向指针(“双指针”)的指针。但是括号外的* 让我感到困惑……下面是上下文中的演员表:

void mem_test ( void )
{
    void* m1;
    void* m2;

    ...

    m1 = 0;

    while ( ( m2 = malloc( 10001 ) ) != 0 )
    {
        *( char** ) m2 = m1;  // what does this cast mean?

        m1 = m2;
    }

    ...
}

它的另一个令人困惑的变体出现在下面的 sn-p 中。演员在这种情况下完成了什么,与上面的有什么不同?

void mpenter ( void );  // a function with no parameters and no return value

...

uchar* code;

...

*( void ( ** ) ( void ) ) ( code - 8 ) = mpenter;  // what does this cast mean?

这种类型的演员的正确名称是什么? IE。我应该搜索什么来了解更多信息?

【问题讨论】:

  • 我会搜索“...这就是我的代码审查失败的原因...”:)
  • 这不是演员阵容的一部分。这是一个单独的取消引用。你见过*ptr = 5;吗?就这样。

标签: c pointers casting function-pointers dereference


【解决方案1】:

mem_test

让我们一步一步地剖析这个问题。为简单起见,假设我们使用 64 位架构,其中指针大小为 8 字节。

  • m2 = malloc( 10001 )m2 分配给新分配的内存块。
  • (char **) m2 说“让我们假设地址 m2 的前 8 个字节内存是 char*,并指向 那个 - 导致 char**
  • *(char **) m2 取消对上述内容的引用,从而导致 char* 的左值(在 C 语言中)。记住 l 值是可写的。
    • 在 C++ 中,它会导致对 char* 的引用,即 char*&
  • *(char **) m2 = m1;m1 的值写入上面创建的 l 值。

编写该代码的另一种方法是:

char* pCurrentBuffer;
char* pPreviousBuffer;

pPreviousBuffer = NULL;
while ( ( pCurrentBuffer = malloc( 10001 ) ) != NULL )
{
    char** ppPreviousBuffer = (char**)pCurrentBuffer;
    *ppPreviousBuffer = pPreviousBuffer;

    pPreviousBuffer = pCurrentBuffer;
}

Surprise(!),最后,它创建了一个链表。 (从技术上讲,这是一个反向链表,因为它们都是前一个指针而不是下一个指针,但我是在开玩笑)

mpenter

这会将地址 code - 8 的 8 个字节转换为指向函数指针的指针,以便它可以将函数 mpenter 的地址分配到该位置。

  • void (*)(void) 是一个指向不带参数并返回 void 的函数的指针。
  • 通过扩展,void (**)(void) 是指向上述类型的函数指针的指针。
  • 解引用产生一个函数指针的左值。
    • 在 C++ 中,它会创建对函数指针的引用,如果这更容易推理的话。
  • 分配它会将mpenter 的地址写入该左值(即地址code - 8 处的8 字节内存)

从指针中获取负偏移量是不寻常的,但如果code 指向某种结构的中间,它可能是合法的(在某种松散的意义上)。

【讨论】:

  • "PS:这段代码真的让我发笑。就像退休忍者的评论一样。"不确定我是否理解幽默或@retired-ninja 的评论...是因为代码 sn-ps 似乎没有做任何有用的事情,还是我对指针语法的混淆...如果是前者,代码 sn-ps 是来自更大程序(onetwo)的小块。如果是后者,我更熟悉隐藏指针的高级语言......
  • 代码 sn-ps 以一种非常迂回的方式做事,而且它们不是类型安全的。大多数人会创建一个 struct Node { Node* pNext; };定义一个链表。 (FWIW 不是在取笑你——我不怪任何人对这段代码感到困惑;我也是)
  • 啊,我明白了。我不理解语法/语法,更不用说逻辑试图做什么了。逻辑可能是找到解决世界和平的方法,我不知道 =)
  • sn-ps 是否可以等效地写为*( ( char** ) m2 )*( ( void ( ** ) ( void ) ) ( code - 8 ) )?外括号有助于在视觉上将强制转换与取消引用 *( (cast)x )... 或添加的外括号改变含义/逻辑?像您一样使用临时变量更具可读性,但很好奇是否可以使用如图所示的一组额外括号来稍微提高易读性。
  • 另外,由于指针运算,我假设最终地址是 (cast)code - 4(cast)(code - 4) 时会有所不同......这是正确的吗?在前一种情况下,它将是-(4*(sizeof(cast_type))),而后一种情况只是普通的旧-4
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 2012-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多