Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 这个使用volatile、指针和内存分配的复杂表达式在后台做什么?_C_Pointers - Fatal编程技术网

C 这个使用volatile、指针和内存分配的复杂表达式在后台做什么?

C 这个使用volatile、指针和内存分配的复杂表达式在后台做什么?,c,pointers,C,Pointers,我知道人们已经回答了什么是volatile,而(int*)只是在施法,但我无法理解这个表达式的真正含义:volatile int*p=(int*)0x0 所以我们有一个指向int的指针p,它的值显然会意外地改变。我们给它分配另一个指向内存地址0的指针?那么,它是指向指针的指针,还是我让它变得比应该的更复杂?如果你能提供这样一个简单的草图,我会非常感激,因为它能帮助我理解 volatile空指针没有太多意义,因为没有人会去引用它 但如果我让这个表达式更有意义(这是STM32微控制器的特定示例) 我

我知道人们已经回答了什么是volatile,而(int*)只是在施法,但我无法理解这个表达式的真正含义:
volatile int*p=(int*)0x0

所以我们有一个指向int的指针p,它的值显然会意外地改变。我们给它分配另一个指向内存地址0的指针?那么,它是指向指针的指针,还是我让它变得比应该的更复杂?如果你能提供这样一个简单的草图,我会非常感激,因为它能帮助我理解


volatile
空指针没有太多意义,因为没有人会去引用它

但如果我让这个表达式更有意义(这是STM32微控制器的特定示例)

我将
volatile
指针
GPIO\u CLR
声明为
uint32\u t
对象。赋值将由无符号长常量定义的该硬件寄存器的地址强制转换为指针类型

0x40010800UL
-硬件寄存器的地址

(volatile uint32\u t*)
-将无符号长地址转换为指针

然后我可以设置或读取这个寄存器的值

volatile int * ptr = (int *) 0x0BADC0DE;
*ptr = 0;
*ptr = 1;

为什么我将此指针定义为
volatile
?因为它可以被硬件改变,编译器不会知道。因此volatile将强制编译器在每次使用前(当我取消引用此指针时)读取此地址下存储的值,并在每次更改后存储它。否则,编译器可能会优化这些读写操作,因为它在正常程序执行路径中不会看到任何影响。

让我们分析这一行

volatile int*p
声明指向
易失性int
的指针。
volatile int
来自存储器,语义为正常的
int
。但是,
volatile
指示编译器,它的值可以随时更改或有其他副作用

在作业的右侧有
(int*)0x0
。这里您告诉编译器,它应该假设一个指向
int
的指针,该指针指向地址
0x0

完整赋值
volatile int*p=(int*)0x0分配
p
0x0
。总之,您告诉编译器,at address
0x0
是一个具有副作用的整数值。它可以通过
*p
访问

不稳定的 你似乎不清楚volatile是什么意思。请看下面的代码:

int * ptr = (int *) 0x0BADC0DE;
*ptr = 0;
*ptr = 1;
优化编译器会对这段代码做一个简短的检查,并说:将
*ptr
设置为
0
没有效果。因此,我们将跳过这一行,只立即分配
1
,以确保执行时间安全,同时收缩二进制文件

因此,编译器实际上只编译以下代码:

int * ptr = (int *) 0x0BADC0DE;
*ptr = 1;
通常情况下,这是可以的,但当我们谈论内存映射的IOs时,情况就不同了

内存映射IO是一些可以通过访问特殊RAM地址来操作的硬件。一个非常简单的例子是一个输出——从处理器引出的一根简单的电线

因此,我们假设在地址
0x0BADC0DE
处有一个内存映射输出。当我们写入
1
时,这个输出被设置为高,当我们写入
0
时,输出被设置为低

当编译器跳过第一个赋值时,输出不会改变。但我们想让另一个组成部分有上升的趋势。在这种情况下,我们希望摆脱优化。一种常见的方法是使用
volatile
关键字。它指示编译器不能检查对此寄存器的读或写访问的每个方面

volatile int * ptr = (int *) 0x0BADC0DE;
*ptr = 0;
*ptr = 1;
现在,编译器不会优化对
*ptr
的访问,我们能够向外部组件发出上升沿信号


内存映射IOs在编写嵌入式系统、操作系统和驱动程序时非常重要。
volatile
关键字的另一个用例是并行计算中的共享变量(除了
volatile
关键字之外,还需要某种信号量互斥来限制对这些变量的同时访问)。

它只是将volatile整数指针初始化为NULL。地址0(NULL)是一个特殊的地址/值,用于指示指针不指向任何对象,因此不应使用它(取消引用)。它是一个指针的赋值——右手侧
(int*)0x0
到另一个指针左手侧
p
,带有一个可变类型限定符。所以,不,
p
不是指向指针的指针。更糟糕的是,实际上有许多系统的地址0是有效寄存器。很久以前,我有一个错误,一个空指针访问错误使微控制器GPIO失控。有时C只是决定射中你的脚。@Marker严格地说,初始化
p
int*
的转换是不正确的,不会产生标准的空指针常量-根据C标准,只有整数零值或整数零值转换到
void*
才是空指针常量。还要注意,
NULL
,虽然也是一个空指针常量,但不必像Lundin上面提到的那样有零值。在我看来,最近在C标准中增加的零值作为空指针常量是对糟糕代码的一种惩罚。@AndrewHenle,我很好奇,在下面哪条语句中p最终没有设置为相同的值?int*p=(int*)0;int*p=(void*)0;int*p=0;请删除第一段。我看不出问题中有足够的信息让你做出直观的飞跃,让指针指向零对这个特定的问题来说有意义还是没有意义