全部博文(21)
分类: C/C++
2010-09-04 20:55:15
The
compilation system tries to reduce code size and execution time on all
machines, by optimizing code. It is programmer responsibility to inform
compilation system that certain code (or variable) should not be
optimized. Many programmers do not understand when to use volatile to
inform compilation system that certain code should not be optimized or
what it does. Although (no doubt) their program work, they do not
exploit the full power of the language.
A
variable should be declared volatile whenever its value can be changed
by something beyond the control of the program in which it appears,
such as a concurrently executing thread. Volatile, can appear only once
in a declaration with any type specifier; however, they cannot appear
after the first comma in a multiple item declaration. For example, the
following declarations are legal
/* Let T denotes some data type */And the following declaration is illegal
typedef volatile T i;
volatile T i;
T volatile i ;
T i, volatile vi ;Volatile qualifiers can be used to change the behavior of a type. For example,
volatile int p = 3;declares and initializes an object with type volatile int whose value will be always read from memory.
Volatile T a =3;The declaration declares and initializes an objet with type volatile T whose value will be always read from memory
T volatile a=3;
Volatile T * ptr;Ptr is a a pointer to a volatile T:
T volatile * ptr;
volatile pointer to a volatile variablevolatile can be applied to derived types such as an array type ,in that case, the element is qualified, not the array type. When applied to struct types entire contents of the struct become volatile. You can apply the volatile qualifier to the individual members of the struct. Type qualifiers are relevant only when accessing identifiers as l-values in expressions. volatile does not affects the range of values or arithmetic properties of the object.. To declare the item pointed to by the pointer as volatile, use a declaration of the form:
int volatile * volatile ptr;
volatile T *vptr;
T* volatile ptrv;
char const ptr=(char*)0X15 ;*ptr access the port consider following code fragment to set the third bit of the output port at periodic intervals
*ptr = 0;the above code may be optimize as
while(*ptr){
*ptr = 4 ;
*ptr = 0 ;
}
*ptr = 0*ptr is assigned 0 before value 4 is used ( and value of *ptr never changes ( same constant is always assigned to it)
while(0) {
}
volatile char * const ptr = (volatile char*)0x16this declaration say the object at which ptr points can change without notice , but that ptr itself is a constant whose value never change
#includethe compiler may use a register to store the num variable in the main thread , so the change to the value by the second thread are ignored . The volatile modifier is a away of telling the compiler that no optimization applied to the variable its value be not placed in register and value may change outside influence during evaluation
#include
volatile int num ;
void* foo()
{
while(1) {
++num ;
sleep(1000);
}
}
main()
{
int p ;
void *targ =NULL ;
thread_t id ;
num = 0;
p = thr_create((void*)NULL , 0,foo,targ,0,&id);
if(!p) printf(" can not create thread ");
while(1)
{
printf("%d" , num ) ;
}
}
#includevolatile variable isn't affected by the optimization. So value of b is after the longjump is the last value variable assigned. Without volatile b may or may not be restored to its last value when the longjmp occurs. For clear understanding assembly listing of above program by cc compiler has been given below.
static jmp_buf buf ;
main( )
{
volatile int b;
b =3 ;
if(setjmp(buf)!=0) {
printf("%d ", b) ;
exit(0);
}
b=5;
longjmp(buf , 1) ;
}
/*Listing1: Assembly code fragment of above program
Produced by cc compiler when volatile is used*/
.file "vol.c"
main:
pushl %ebp
movl %esp, %ebp
subl $20, %esp
movl $3, -4(%ebp)
pushl $buf
call _setjmp
addl $16, %esp
testl %eax, %eax
je .L18
subl $8, %esp
movl -4(%ebp), %eax
pushl %eax
pushl $.LC0
call printf
movl $0, (%esp)
call exit
.p2align 2
.L18:
movl $5, -4(%ebp)
subl $8, %esp
pushl $1
pushl $buf
call longjmp
/*Listing 2:Assemply code fragment of above program
produced by cc compile witout volatile keword */
.file "wvol.c"
main:
pushl %ebp
movl %esp, %ebp
subl $20, %esp
pushl $buf
call _setjmp
addl $16, %esp
testl %eax, %eax
je .L18
subl $8, %esp
pushl $3
pushl $.LC0
call printf
movl $0, (%esp)
call exit
.p2align 2
.L18:
subl $8, %esp
pushl $1
pushl $buf
call longjmp
/listing 3: difference between listing 1 and listing 3 ***/
< .file "vol.c"
---
> .file "wvol.c"
< movl $3, -4(%ebp)
< movl -4(%ebp), %eax
< pushl %eax
> pushl $3
< movl $5, -4(%ebp) / * store in stack */
static lon int num ;When compilation system execute while statement, the optimizer in compiler may notice that it read the value num once already and that value is still in the register. Instead of re reading the value from memory, compiler may produce code to use the (possibly messed up) value in the register defeating purpose of original C program. Some compiler may optimize entire while loop assuming that since the value of num was just assigned to val , the two must be equal and condition in while statement will therefore always be false .To avoid this ,you have to declare num to be volatile that warns compilers that certain variables may change because of interrupt routines.
void interrupt update(void)
{
++num ;
}
main()
{
long val ;
val = num ;
while(val !=num)
val = num ;
rturn val ;
}
static volatile long int num ;With volatile keyword in the declaration the compiler knows that the value of num must b read from memory every time it is referenced.