强制转换中的中间指针必须是“常量限定”的。 -为什么? [英] Intermediate pointers in cast must be "const qualified" - why?

查看:110
本文介绍了强制转换中的中间指针必须是“常量限定”的。 -为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下代码中...

#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 中的 p 进行危险访问。照原样,该代码指示编译器发出安全的代码,可以优化对 * p 的重复读取访问,这确实是错误的。

...the compiler rightfully detects that any potential accesses to the data pointed to by p inside work are dangerous accesses. As-is, the code instructs the compiler that it is safe to emit code that optimizes away repeated read accesses to *p - which is indeed wrong.

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

But the weird thing is, that the warning emitted by compiling this code...

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

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

...doesn't complain about the loss of volatile - it instead recommends using 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 在这里很有意义。

I cannot see how const makes sense here.

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

P.S. Note that adding volatile in front of the uint32_t *p, as expected, fixes the issue. My question is why GCC recommends const instead of volatile.

推荐答案

好吧,我举了票在GCC的Bugzilla中关于此问题……约瑟夫·迈尔斯(Joseph Myers)给出了一个简洁的答案:

Well, I raised a ticket in GCC's Bugzilla about this... and Joseph Myers has answered with a laconic answer:


不,GCC并不感到困惑。就是说将
uint32_t ** 转换为 volatile uint32_t * const * 是类型安全的,但是不要将其转换为
volatile uint32_t *

No, GCC is not confused. It's saying that it's type-safe to convert uint32_t ** to volatile uint32_t *const *, but not to convert it to volatile uint32_t *.

。 ..他还添加了对 C常见问题解答这一部分的引用。

...and he also added a reference to this part of the C FAQ.

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

I have to admit that my first reaction to this was a "say what?". I quickly tested the suggestion, changing the code to make it use the proposed declaration (and cast) instead...

#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

$ 

...而且确实不再发出警告。

...and indeed, no warning anymore.

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

So I went ahead and read the relevant FAQ - and I think I understand a bit more of what is happening. By adding the const modifier, the parameter we are passing is (reading from right to left, as we're supposed to do in this kind of C syntax):


指向恒定指针(永远不变)的指针,该指针指向易失数据

a pointer to a constant pointer (that will never change) that points to volatile data

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

This indeed maps very well to what is happening here: I am getting a pointer that points to volatile data, that is a driver-provided buffer - i.e. one that I indeed am not allowed to change, since it comes from pre-allocated lists of buffers that the driver itself allocated. Modifying the pointer that get_buffer_from_HW_driver returned would make no sense; it's not mine to modify, I can only use it as-is.

我承认,我对C的类型系统感到非常惊讶(增强了C的强大的静态分析检查功能) -wcast-qual)实际上可以帮助保证这些语义。

I confess I am really surprised that C's typesystem (augmented with the really strong static-analysis checks of -Wcast-qual) can actually help in guaranteeing these semantics.

非常感谢Joseph-我将把这个问题开放几个星期,以防其他人想要详细说明。

Many thanks to Joseph - and I'll leave the question open for a few weeks, in case someone else wants to elaborate more.

P.S。补充一点:从现在开始,当有人声称C是一种简单的语言时,我想将它们指向此处。

这篇关于强制转换中的中间指针必须是“常量限定”的。 -为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆