volatile
可能很多人都没用过C/C++中的这个关键词,甚至不知道它的存在,本人以前也只是有所耳闻,但似懂非懂。
这是一个类型修饰符,位置同const、static等。一个使用volatile修饰的变量,比如volatile int i; 每次对该变量的直接引用,都会访问内存,而不是从寄存器中读取(如果其已经在寄存器中)。这样一来,volatile似乎没什么用处,反倒会使数据的读取相对变慢很多。但是,如果没有volatile,编译器可能会优化你的程序,使得数据从寄存器中读取,从而加快程序的运行,但如果这个变量是同其它进程/线程共享的,就可能造成数据的不一致。多线程情况下,你可以使用互斥机制来保证对共享数据访问的原子性。但是,在单片机等嵌入式环境中,硬件经常不会有这种互斥机制的支持,这时某些共享的数据(比如端口)就可能会产生不一致的情况。而使用volatile就会使编译器不对代码进行优化,每次对该变量的访问都会从内存中读取。
下面通过观察使用volatile前后编译产生的汇编代码的不同,来加深对volatile关键词的理解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [ ... ] main: [ ... ] call foo # 调用函数foo,返回值保存至寄存器eax movl %eax, 44(%esp) # 为i赋值 movl 44(%esp), %edx # 读取i值 movl 44(%esp), %ecx # 读取i值 movl 44(%esp), %eax # 读取i值 movl %ecx, 16(%esp) # 参数k入栈,使用i值 movl %edx, 12(%esp) # 参数j入栈,使用i值 movl %eax, 8(%esp) # 参数i入栈 movl $.LC0, 4(%esp) # 格式字符串地址入栈 call __printf_chk movl $0, %eax leave ret [ ... ] |
, Distant[s]为0;
,另有一个栈Stack和一个队列Queue,Stack与Queue初始为空。现对S中元素依次进行如下操作:
个这样的序列。但是,这里的01序列是建立在一些列的入栈出栈操作的基础上的,因此就会受到入栈、出栈操作的限制。这里,唯一的限制就是栈为空时,无法进行出栈操作。反映到这个01序列中就是,任意位置之前,0的个数都能比1的个数多。因为有了01序列的总数