在以下代码中...
#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
。
好吧,我在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] 删除。
我来说两句