-
< c primer plus > 书上的一段话,请前辈不吝执教,const 和 volatile怎么能同时定义一个变量呢,不明白。谢谢。
一个值可以同时是vonst和volatile。例如,硬件时钟一般设定为不能由程序改变,这一点使他成为const; 但它被程序以外的代理改变,这使它成为volatile的。只需在声明中同时使用这两个限定词,如下所示,顺序并不重要:
volatile const int ioc;
const volatile int *ploc;
问题点数: 12分
CSDN今日推荐
回复于 2007-12-10 14:25:44
#1 得分:0
lz第2行开始的一段话好像是贴出来的,我觉得这段话已经把原因说得很清楚了。
回复于 2007-12-10 14:27:50
#2 得分:0
他是说了,但我不理解,呵呵。 const 是为了不变的目的而进入ANSI C, 而volatile是可变的含义, 总是觉得两者冲突。
回复于 2007-12-10 14:31:18
#3 得分:0
具体说,作者的解释 ”但它被程序以外的代理改变,这使它成为volatile的“ 这句话,没理解。其他程序把硬件时钟改变了?即把定义为const的一个时钟变量的值改了,是吗,而const定义的常量的值是不允许改动的呀?究竟把什么改了呢?
回复于 2007-12-10 14:38:31
#4 得分:4
volatile标识一个变量意味着这个变量可能被非本程序的其他过程改变,例如某个访问这一变量的某中断程序。为变量加上这一标识可以禁止编译器的优化,使程序正确地按设计者的意图运行。例如下面的程序,我们将intr_func注册为中断函数,某个中断发生时触发这一函数:
unsigned char flag = 1;
int main(int argc, char **argv) {
reg_intr(XXX, intr_func);
while(flag) {
printf("hello\n");
}
return 0;
}
void intr_func(void) {
flag = 0;
}
当不加volatile时,编译器会直接将while条件中的flag换成1,因此即使中断发生也无法结束循环;如果给flag加上volatile标识,编译器就不会做前述的优化,程序得以按设计的意图工作。
unsigned char flag = 1;
int main(int argc, char **argv) {
reg_intr(XXX, intr_func);
while(flag) {
printf("hello\n");
}
return 0;
}
void intr_func(void) {
flag = 0;
}
当不加volatile时,编译器会直接将while条件中的flag换成1,因此即使中断发生也无法结束循环;如果给flag加上volatile标识,编译器就不会做前述的优化,程序得以按设计的意图工作。
回复于 2007-12-10 14:43:19
#5 得分:0
续
如果一个变量不会被本程序改变,通常可能给它加上const,但如果该变量可能被其他程序改变而本程序又在检测这个变量的值,就需要给它加上volatile,于是变量就同时有volatile和const了。
如果一个变量不会被本程序改变,通常可能给它加上const,但如果该变量可能被其他程序改变而本程序又在检测这个变量的值,就需要给它加上volatile,于是变量就同时有volatile和const了。
回复于 2007-12-10 14:44:40
#6 得分:0
不好意思,本人语文不太好,不知道意思说清楚没。
回复于 2007-12-10 14:47:34
#7 得分:0
const是给编译器看的,作为编译期间检查用
那句话我倒是明白,但也不是完全理解
那句话我倒是明白,但也不是完全理解
回复于 2007-12-10 14:54:32
#8 得分:0
const volatile int *ploc;
这个感觉还有点意义
volatile const int ioc;
想不出这个做什么用
得回去试试
这个感觉还有点意义
volatile const int ioc;
想不出这个做什么用
得回去试试
回复于 2007-12-10 15:01:58
#9 得分:0
const表示我们自己的代码不会改变这个值(别的代码或者硬件有可能改变这个值)。volatile表示禁止优化。因为编译器会认为如果代码没有改变变量,那么这个变量就不会改变,因此编译器会用寄存器把该变量缓存起来,每次需要读取变量值的时候,就从缓存中读取。这在大多数时候是正确的,但是在多线程或者中断的场合就不正确了。
回复于 2007-12-10 15:16:17
#10 得分:0
reg_intr(XXX, intr_func); 这个函数,是什么?
回复于 2007-12-10 15:21:11
#11 得分:0
Jim_King_2000 你说的“因为编译器会认为如果代码没有改变变量,那么这个变量就不会改变,因此编译器会用寄存器把该变量缓存起来,每次需要读取变量值的时候,就从缓存中读取。” 这句话的前提是 没有使用volatile, 才使用寄存器吧?
如果使用volatile,就应该直接从初始的内存区 去读数据吧。
如果使用volatile,就应该直接从初始的内存区 去读数据吧。
回复于 2007-12-10 15:24:38
#12 得分:0
To skywarship :
李哥 写的 那段程序段 有的地方没看明白 :
reg_intr(XXX, intr_func); 这个函数,是什么?
如果使用volatile的话, 是把flag的定义变为 volatile unsigned char flag = 1; 是这样么?
李哥 写的 那段程序段 有的地方没看明白 :
reg_intr(XXX, intr_func); 这个函数,是什么?
如果使用volatile的话, 是把flag的定义变为 volatile unsigned char flag = 1; 是这样么?
回复于 2007-12-10 15:30:46
#13 得分:0
const是只读的意思,被const定义的变量一般被认为无法修改(如果想修改也是可以的)
而
volatile是易变的,被volatile定义的变量一般认为是易改变的,因此编译器对其声明或定义的变量
不会进行优化,何为优化?就是为了提高运算速度,编译器对代码进行的代码优化
这2个关键字本身并没有使用上的冲突。
而
volatile是易变的,被volatile定义的变量一般认为是易改变的,因此编译器对其声明或定义的变量
不会进行优化,何为优化?就是为了提高运算速度,编译器对代码进行的代码优化
这2个关键字本身并没有使用上的冲突。
回复于 2007-12-10 16:01:43
#15 得分:0
to wendy_welcom
Jim_King_2000 你说的“因为编译器会认为如果代码没有改变变量,那么这个变量就不会改变,因此编译器会用寄存器把该变量缓存起来,每次需要读取变量值的时候,就从缓存中读取。” 这句话的前提是 没有使用volatile, 才使用寄存器吧?
如果使用volatile,就应该直接从初始的内存区 去读数据吧。
=========================================
对
Jim_King_2000 你说的“因为编译器会认为如果代码没有改变变量,那么这个变量就不会改变,因此编译器会用寄存器把该变量缓存起来,每次需要读取变量值的时候,就从缓存中读取。” 这句话的前提是 没有使用volatile, 才使用寄存器吧?
如果使用volatile,就应该直接从初始的内存区 去读数据吧。
=========================================
对
回复于 2007-12-10 16:02:27
#16 得分:0
我好象记得在C#中写多线程程序时, 有的时候要把某变量设为volatile,
已使得另一线程可以改变它的值.
如果记错了请狠狠地批评我
已使得另一线程可以改变它的值.
如果记错了请狠狠地批评我
回复于 2007-12-10 16:10:48
#17 得分:0
我想问的问题就在这儿, volatile 目的是允许其他程序改变该变量的值。 而const 目的是把该值变为常量,不允许变动, const volatile int a; 这两个关键字放在一起为什么不矛盾呢?
难道是把a 存放在两个地方, 寄存器里的a是变量,内存里的a的值是常量? 是这样么?
加上volatile后, 还能从寄存器里面读取a 么?
难道是把a 存放在两个地方, 寄存器里的a是变量,内存里的a的值是常量? 是这样么?
加上volatile后, 还能从寄存器里面读取a 么?
回复于 2007-12-10 16:12:19
#18 得分:3
发表于:2007-12-10 15:55:4514楼 得分:0
只读不就是不允许修改么?
=====================
不允许这里修改不代表不允许别处修改,再比如:
int i = 5;
const int* p = &i;
*p = 6; // 不可以;
i = 7; // 完全可以,而且那个“const”的“*p”也跟着变成了7。
只读不就是不允许修改么?
=====================
不允许这里修改不代表不允许别处修改,再比如:
int i = 5;
const int* p = &i;
*p = 6; // 不可以;
i = 7; // 完全可以,而且那个“const”的“*p”也跟着变成了7。
回复于 2007-12-10 16:14:31
#19 得分:0
const和volatile放在一起的意义在于:
(1)本程序段中不能对a作修改,任何修改都是非法的,或者至少是粗心,编译器应该报错,防止这种粗心;
(2)另一个程序段则完全有可能修改,因此编译器最好不要做太激进的优化。
(1)本程序段中不能对a作修改,任何修改都是非法的,或者至少是粗心,编译器应该报错,防止这种粗心;
(2)另一个程序段则完全有可能修改,因此编译器最好不要做太激进的优化。
回复于 2007-12-10 16:17:07
#20 得分:0
“const”含义是“请做为常量使用”,而并非“放心吧,那肯定是个常量”。
“volatile”的含义是“请不要做没谱的优化,这个值可能变掉的”,而并非“你可以修改这个值”。
因此,它们本来就不是矛盾的啊。
“volatile”的含义是“请不要做没谱的优化,这个值可能变掉的”,而并非“你可以修改这个值”。
因此,它们本来就不是矛盾的啊。
回复于 2007-12-10 16:23:52
#21 得分:5
只读表示编译器不允许代码修改变量。但并不表示这个变量在其它地方不能够被修改(不能被修改岂不就成了常量?)。比如:
在上面的程序中,str所指向的内存区域就是只读的,但这个只读性只在函数f内部,出了f,这块内存完全有可能是能够被修改的。
另外一个例子在嵌入式系统中比较常见。很多嵌入式系统允许我们访问外部寄存器,该寄存器的地址可能是0x0018,该寄存器的最低位可能表示设备状态,1为忙碌,0为空闲。
这段代码很可能会死循环。因为编译器强奸民意的将地址0x0018处的值缓存起来,然后每次while的时候都从缓存中读取。虽然STATUS_REG的值是const unsigned char *,但这仅仅表示STATUS_REG寄存器是个只读寄存器,我们不能够在代码中去写这个寄存器,但并不表示这个寄存器是不能够改变的。硬件完成了它的任务之后,就会把状态设置成空闲,因此该寄存器的最后一位在我们循环的时候很可能已经发生了变化。因此在这样的地方,我们要禁止编译器自作聪明的优化,方法如下:
1
2
3
4
|
void
f(
const
char
*str)
{
...
}
|
在上面的程序中,str所指向的内存区域就是只读的,但这个只读性只在函数f内部,出了f,这块内存完全有可能是能够被修改的。
1
2
3
4
5
6
|
void
g(
void
)
{
char
name[] =
"Jim King"
;
f(name);
...
}
|
另外一个例子在嵌入式系统中比较常见。很多嵌入式系统允许我们访问外部寄存器,该寄存器的地址可能是0x0018,该寄存器的最低位可能表示设备状态,1为忙碌,0为空闲。
1
2
3
4
5
6
|
#define GET_REG_VALUE(reg) (*reg) /* get register value */
const
unsigned
char
*STATUS_REG = 0x0018;
/* status register */
const
unsigned
char
STATUS_BUSY = 0x01;
/* busy bit */
while
(GET_REG_VALUE(STATUS_REG) & STATUS_BUSY);
/* wait until free */
// do something to operate the device
...
|
这段代码很可能会死循环。因为编译器强奸民意的将地址0x0018处的值缓存起来,然后每次while的时候都从缓存中读取。虽然STATUS_REG的值是const unsigned char *,但这仅仅表示STATUS_REG寄存器是个只读寄存器,我们不能够在代码中去写这个寄存器,但并不表示这个寄存器是不能够改变的。硬件完成了它的任务之后,就会把状态设置成空闲,因此该寄存器的最后一位在我们循环的时候很可能已经发生了变化。因此在这样的地方,我们要禁止编译器自作聪明的优化,方法如下:
1
|
const
volatile
unsigned
char
*STATUS_REG = 0x0018;
/* status register */
|
回复于 2007-12-10 16:26:58
#22 得分:0
咦?我刚回复了下怎么没了?
-------------
想到了在C#中使用过volatile: (以下摘自MSDN)
volatile 关键字表示字段可能被多个并发执行线程修改。声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值。
volatile 修饰符通常用于由多个线程访问而不使用 lock 语句(C# 参考) 语句对访问进行序列化的字段。
所以,如果用const volatile两个关键词声明变量,
则指明该变量不能在声明它的线程中被修改,
而可以被其他线程所修改.C#以外的语言等待道理类似.
我的理解.
-------------
想到了在C#中使用过volatile: (以下摘自MSDN)
volatile 关键字表示字段可能被多个并发执行线程修改。声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值。
volatile 修饰符通常用于由多个线程访问而不使用 lock 语句(C# 参考) 语句对访问进行序列化的字段。
所以,如果用const volatile两个关键词声明变量,
则指明该变量不能在声明它的线程中被修改,
而可以被其他线程所修改.C#以外的语言等待道理类似.
我的理解.
回复于 2007-12-10 16:30:32
#23 得分:0
const volatile int *p; 可以理解
const volatile int a; 怎么解释呢?
a 这个变量不能改变这个地址的值,别的变量可以改变? const volatile int a=4;
int b=a;
a=6; //错误
b=6; // 正确
请问我这样理解对么?
const volatile int a; 怎么解释呢?
a 这个变量不能改变这个地址的值,别的变量可以改变? const volatile int a=4;
int b=a;
a=6; //错误
b=6; // 正确
请问我这样理解对么?
回复于 2007-12-10 16:34:05
#24 得分:0
const volatile int a;应该来说很少会遇到吧?在这里没有必要加上volatile的。
回复于 2007-12-10 16:41:49
#25 得分:0
skywarship
Jim_King_2000
steedhorse
几位兄台都说得很明白了
Jim_King_2000
steedhorse
几位兄台都说得很明白了
回复于 2007-12-10 16:55:10
#26 得分:0
const volatile int a is uaually used in multithreading and Interrupt Service Program.
回复于 2007-12-10 17:05:41
#29 得分:0
只不过需要明白“volatile”的含义并非是“non-const”。所以他们才可以放在一起。
在C++语言中,const没有反义词,如果一个变量没有const修饰,那它本身就是const的反义词,而并非加上volatile才是const的反义词。
在C++语言中,const没有反义词,如果一个变量没有const修饰,那它本身就是const的反义词,而并非加上volatile才是const的反义词。
回复于 2007-12-10 17:17:59
#30 得分:0
这个非常类似 static 修饰变量的时候,如果只是声明,可以这样写;
那么以后,赋过初值了就不可以再变了;OK?
那么以后,赋过初值了就不可以再变了;OK?
回复于 2007-12-10 23:08:20
#33 得分:0
The code with volatile is more likely to break at optimization. For example, the following code may not print what you think it should be with this type qualifier.
1
2
3
4
5
6
7
8
9
|
int
main(
void
)
{
int
volatile
const
len = 10;
int
m;
m = len * 2;
printf
(
"%d\n"
, m);
return
0;
}
|
回复于 2007-12-11 00:57:34
#34 得分:0
ls的英文太糟糕了,no offence,but...建议你用中文翻译一下吧,老子看不懂。
“volatile const int ioc”
这个通常用于声明,而不是定义,比如:
file A:
int ioc;//定义变量
file B:
extern volatile const int ioc;//
或许file C:
extern volatile int ioc;//
这样B不能修改ioc,且每次读取ioc的时候都会从内存里读。
不过上面的例子在VC上不能运行,因为VC试图保证联接的时候的类型安全(无聊的决策),gcc是没有问题的
“volatile const int ioc”
这个通常用于声明,而不是定义,比如:
file A:
int ioc;//定义变量
file B:
extern volatile const int ioc;//
或许file C:
extern volatile int ioc;//
这样B不能修改ioc,且每次读取ioc的时候都会从内存里读。
不过上面的例子在VC上不能运行,因为VC试图保证联接的时候的类型安全(无聊的决策),gcc是没有问题的
回复于 2007-12-11 10:46:49
#36 得分:0
举个简单的例子。只读的状态寄存器,它是volatile,因为它可能被意想不到地改变。
它是const,因为程序不应该试图去修改它。
它是const,因为程序不应该试图去修改它。
回复于 2007-12-11 11:17:06
#37 得分:0
对于const来说,应该理解为
只读的意思,如果一个变量被定义为const了,那么它告诉使用者这个变量是只读的,不要试图在当前的模块中改变它。
而对于volatile来说,它是告诉编译器,这个被声明的变量可能在本程序之外被修改,告诉编译器每次在使用这个变量的时候都需要重新加载,不能优化。
举个例子:
我们现在有个变量A ,它表示的是一个寄存器的内容,而在我们的程序当中如果是不可以修改寄存器内容的,因此A应该声明为const,而寄存器的值是和外设相关的,是不受我们程序控制的,程序可能只是检测这个值,因此A又应该设置为volatile。
本人愚见,忘高手赐教!
而对于volatile来说,它是告诉编译器,这个被声明的变量可能在本程序之外被修改,告诉编译器每次在使用这个变量的时候都需要重新加载,不能优化。
举个例子:
我们现在有个变量A ,它表示的是一个寄存器的内容,而在我们的程序当中如果是不可以修改寄存器内容的,因此A应该声明为const,而寄存器的值是和外设相关的,是不受我们程序控制的,程序可能只是检测这个值,因此A又应该设置为volatile。
本人愚见,忘高手赐教!
回复于 2007-12-11 11:21:25
#38 得分:0
对于const来说,应该理解为
只读的意思,如果一个变量被定义为const了,那么它告诉使用者这个变量是只读的,不要试图在当前的模块中改变它。
而对于volatile来说,它是告诉编译器,这个被声明的变量可能在本程序之外被修改,告诉编译器每次在使用这个变量的时候都需要重新加载,不能优化。
举个例子:
我们现在有个变量A ,它表示的是一个寄存器的内容,而在我们的程序当中如果是不可以修改寄存器内容的,因此A应该声明为const,而寄存器的值是和外设相关的,是不受我们程序控制的,程序可能只是检测这个值,因此A又应该设置为volatile。
本人愚见,忘高手赐教!
而对于volatile来说,它是告诉编译器,这个被声明的变量可能在本程序之外被修改,告诉编译器每次在使用这个变量的时候都需要重新加载,不能优化。
举个例子:
我们现在有个变量A ,它表示的是一个寄存器的内容,而在我们的程序当中如果是不可以修改寄存器内容的,因此A应该声明为const,而寄存器的值是和外设相关的,是不受我们程序控制的,程序可能只是检测这个值,因此A又应该设置为volatile。
本人愚见,忘高手赐教!
回复于 2007-12-11 22:00:38
#39 得分:0
const:变量不能为代码直接修改,但可以间接或通过外部的一些触发(如管脚或寄存器等).
volatile:编译器不能假设程序在运行中执有变量的一个副本.
volatile:编译器不能假设程序在运行中执有变量的一个副本.
回复于 2007-12-11 22:02:14
#40 得分:0
> JobSeeker
> 朋友的淘宝网
> 等 级:
> 发表于:2007-12-11 00:57:3434楼 得分:0
> ls的英文太糟糕了,no offence,but...建议你用中文翻译一下吧,老子看不懂。
>
You're not expected to understand that because you're a fool. You know neither English language nor the C language.
> “volatile const int ioc”
> 这个通常用于声明,而不是定义,比如:
> file A:
> int ioc;//定义变量
>
> file B:
> extern volatile const int ioc;//
>
> 或许file C:
> extern volatile int ioc;//
>
> 这样B不能修改ioc,且每次读取ioc的时候都会从内存里读。
>
> 不过上面的例子在VC上不能运行,因为VC试图保证联接的时候的类型安全(无聊的决策),gcc是没有问题的
>
You told people that you're really a fool by presenting this rubbish.
By the way, if there're some people can explain why that fool was wrong with that code, they will be given awards :-D
> 朋友的淘宝网
> 等 级:
> 发表于:2007-12-11 00:57:3434楼 得分:0
> ls的英文太糟糕了,no offence,but...建议你用中文翻译一下吧,老子看不懂。
>
You're not expected to understand that because you're a fool. You know neither English language nor the C language.
> “volatile const int ioc”
> 这个通常用于声明,而不是定义,比如:
> file A:
> int ioc;//定义变量
>
> file B:
> extern volatile const int ioc;//
>
> 或许file C:
> extern volatile int ioc;//
>
> 这样B不能修改ioc,且每次读取ioc的时候都会从内存里读。
>
> 不过上面的例子在VC上不能运行,因为VC试图保证联接的时候的类型安全(无聊的决策),gcc是没有问题的
>
You told people that you're really a fool by presenting this rubbish.
By the way, if there're some people can explain why that fool was wrong with that code, they will be given awards :-D
回复于 2007-12-13 08:57:05
#41 得分:0
const说的是不让你改,并没有说不让别的东西改;而volatile说的就是可能会被别人改的。