我认为以下内容会给我10个不稳定的整数
volatile int foo[10];
但是,我认为以下内容不会做同样的事情。
volatile int* foo;
foo = malloc(sizeof(int)*10);
如果我错了,请纠正我,以及我如何使用malloc获得一系列不稳定的项目。
感谢。
答案 0 :(得分:12)
int volatile * foo;
从右到左阅读“foo是一个指向volatile int的指针”
所以无论你通过foo访问什么int,int都将是不稳定的。
P.S。
int * volatile foo; // "foo is a volatile pointer to an int"
==
volatile int * foo; // foo is a pointer to an int, volatile
意思是foo是不稳定的。第二种情况实际上只是一般的从右到左规则的剩余部分。 要吸取的教训是养成使用
的习惯char const * foo;
而不是更常见的
const char * foo;
如果你想要更复杂的东西,比如“指向函数返回指向int的指针”,那就没有任何意义了。
P.S。,这是一个巨大的(我正在添加答案的主要原因):
我注意到你将“多线程”作为标记包含在内。你是否意识到volatile在多线程方面几乎没有什么好处?
答案 1 :(得分:6)
volatile int* foo;
是要走的路。 volatile 类型限定符的工作方式与 const 类型限定符的工作方式类似。如果你想要一个指向常量数组的指针,你会写:
const int* foo;
,而
int* const foo;
是一个指向整数的常量指针,该整数本身可以更改。 volatile 的工作方式相同。
答案 2 :(得分:3)
是的,那会有效。实际内存volatile
没有什么不同。这只是一种告诉编译器如何与该内存进行交互的方法。
答案 3 :(得分:2)
我认为第二个声明指针是易失性的,而不是指向的指针。为此,我认为应该是
int * volatile foo;
gcc
可接受此语法,但我遇到问题convincing myself它会做出不同的事情。
我发现gcc -O3
(完全优化)存在差异。对于这个(愚蠢的)测试代码:
volatile int v [10];
int * volatile p;
int main (void)
{
v [3] = p [2];
p [3] = v [2];
return 0;
}
使用volatile
,并省略(x86)不会更改的指令:
movl p, %eax
movl 8(%eax), %eax
movl %eax, v+12
movl p, %edx
movl v+8, %eax
movl %eax, 12(%edx)
没有volatile,它会跳过重新加载p
:
movl p, %eax
movl 8(%eax), %edx ; different since p being preserved
movl %edx, v+12
; 'p' not reloaded here
movl v+8, %edx
movl %edx, 12(%eax) ; p reused
经过多次尝试寻找差异的科学实验后,我得出结论,没有区别。 volatile
关闭与变量相关的所有优化,这些优化将重用随后设置的值。至少使用x86 gcc(GCC)4.1.2 20070925(Red Hat 4.1.2-33)。 : - )
答案 4 :(得分:1)
非常感谢wallyk,我能够设计一些代码,使用他的方法生成一些程序集来向自己证明不同指针方法之间的区别。
使用代码:并使用-03
进行编译int main (void)
{
while(p[2]);
return 0;
}
当p被简单地声明为指针时,我们陷入了一个无法摆脱的循环中。请注意,如果这是一个多线程程序而另一个线程写入p [2] = 0,则程序将跳出while循环并正常终止。
int * p;
============
LCFI1:
movq _p(%rip), %rax
movl 8(%rax), %eax
testl %eax, %eax
jne L6
xorl %eax, %eax
leave
ret
L6:
jmp L6
请注意,L6的唯一指令是转到L6。
当p是易失性指针
时int * volatile p;
==============
L3:
movq _p(%rip), %rax
movl 8(%rax), %eax
testl %eax, %eax
jne L3
xorl %eax, %eax
leave
ret
这里,指针p在每次循环迭代时重新加载,因此数组项也会重新加载。但是,如果我们想要一个易失整数的数组,这将是不正确的,因为这是可能的:
int* volatile p;
..
..
int* j;
j = &p[2];
while(j);
并且会导致在多线程程序中无法终止的循环。
最后,这是正确的解决方案,因为tony很好地解释了。
int volatile * p;
LCFI1:
movq _p(%rip), %rdx
addq $8, %rdx
.align 4,0x90
L3:
movl (%rdx), %eax
testl %eax, %eax
jne L3
leave
ret
在这种情况下,p [2]的地址保存在寄存器值中,而不是从存储器加载,但p [2]的值在每个循环周期从内存重新加载。
还要注意
int volatile * p;
..
..
int* j;
j = &p[2];
while(j);
将生成编译错误。