强制转换中的中间指针必须是“ const限定”的-为什么?

s

在以下代码中...

#include <stdlib.h>
#include <stdint.h>

extern void get_buffer_from_HW_driver(volatile uint32_t **p);

void getBuffer(volatile uint32_t **pp)
{
    // Write an address into pp, that is obtained from a driver
    // The underlying HW will be DMA-ing into this address,
    // so the data pointed-to by the pointer returned by this
    // call are volatile.
    get_buffer_from_HW_driver(pp);
}

void work()
{
    uint32_t *p = NULL;
    getBuffer((volatile uint32_t **)&p);
}

...编译器正确地检测到p内部指向的数据的任何潜在访问work都是危险的访问。照原样,该代码指示编译器发出安全的代码,可以优化对重复读取的访问,*p这是错误的。

但是奇怪的是,通过编译此代码发出的警告...

$ gcc -c -Wall -Wextra -Wcast-qual constqual.c

...不抱怨丢失volatile-它建议使用const

constqual.c: In function ‘work’:
constqual.c:20:15: warning: to be safe all intermediate pointers in cast from 
                   ‘uint32_t ** {aka unsigned int **}’ to ‘volatile uint32_t ** 
                   {aka volatile unsigned int **}’ must be ‘const’ qualified
                   [-Wcast-qual]
 getBuffer((volatile uint32_t **)&p);
           ^

我看不到const这里有什么道理。

PS请注意,按预期volatile在前面添加uint32_t *p可解决此问题。我的问题是,为什么GCC建议使用const而不是volatile

s

好吧,我在GCC的Bugzilla上举了一张与此有关的票……而约瑟夫·迈尔斯(Joseph Myers)给出了一个简洁的答案:

不,海湾合作委员会不感到困惑。就是说转换uint32_t **类型安全volatile uint32_t *const *,但不能转换类型安全volatile uint32_t *

...并且他还添加了对C FAQ的这一部分的引用

我必须承认,对此我的第一反应是“说什么?” 我迅速测试了该建议,更改了代码,使其改为使用建议的声明(并强制转换)...

#include <stdlib.h>
#include <stdint.h>

extern void get_buffer_from_HW_driver(volatile uint32_t * const *p);
void getBuffer(volatile uint32_t * const *pp)
{
    // Write an address into pp, that is obtained from a driver
    // The underlying HW will be DMA-ing into this address,
    // so the data pointed-to by the pointer returned by this
    // call are volatile.
    get_buffer_from_HW_driver(pp);
}

void work()
{
    uint32_t *p = NULL;
    getBuffer((volatile uint32_t * const *)&p);
}

$ gcc -c -Wall -Wextra -Wcast-qual constqual.c

$ 

...的确,再也没有警告。

因此,我继续阅读相关的常见问题解答-我想我对所发生的事情了解得更多。通过添加const修饰符,我们传递的参数是(从右到左读取,就像我们应该使用这种C语法那样)

指向常量指针的指针(永远不变),常量指针指向易失性数据

这确实很好地映射了这里发生的事情:我得到了一个指向易失性数据的指针,该指针是驱动程序提供的缓冲区-即我确实不允许更改的指针,因为它来自预先分配的列表。驱动程序本身分配的缓冲区。修改get_buffer_from_HW_driver返回的指针毫无意义。这不是我的修改,我只能原样使用。

我承认我真的很惊讶C的类型系统(通过对-Wcast-qual的真正强大的静态分析检查的增强)实际上可以帮助保证这些语义。

非常感谢约瑟夫-我将把这个问题搁置几个星期,以防其他人想详细说明。

PS添加一个心理注释:从现在开始,当任何人声称C是一种简单的语言时,我想我会在这里指出。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

是什么在C const限定符和C ++中的const限定符之间的区别?

为什么在此类型别名中删除const限定符?

从 'void *' 到 'const std::string *&' 必须有所有中间指针 const 限定

C中const限定函数指针的行为

“非 const 限定”是什么意思?

对于const限定指针,restrict冗余吗?

为什么我得到“从const指针到指针的无效转换?”

为什么const右值限定的std :: optional :: value()返回const右值引用?

为什么std :: remove_const不删除const限定词?

C 中 const 限定函数的行为

转换 const 指针时是否保留了 c 中的 const 限定符?

为什么允许在初始化列表中从const指针到const到const指针到非常量的转换

指针数组中C ++中的const限定符

为什么调用此ref限定的用户定义转换?

为什么将const指针意外转换为bool?

为什么`const`限定词在此初始化中被丢弃?

不明白为什么const限定词会被丢弃

为什么const限定符警告取决于变量内容而不是类型?

为什么const限定词允许临时对象或右值?

为什么返回类型上的'const'限定词对以__forceinline / inline标记的函数不起作用?

为什么const必须在typescript中的export类之外?

为什么参数中的默认char *必须为const?

为什么在将值打印到地址位于指针中的内存中之前,必须将void指针强制转换为int或其他内容?

ref限定符`const &&`的用途是什么?

const限定词的正确用法是什么?

多个const限定词是什么意思?

为什么初始化指针时必须将数组强制转换为type []?

为什么必须连续对可变的原始指针执行两次强制转换?

为什么const指针的向量在c ++ 17中起作用