5 回答
该volatile
关键字旨在应用于表示存储的对象而不是函数。从函数返回 avolatile int
没有多大意义。函数的返回值不会被优化掉(内联函数可能例外,但这完全是另一种情况......),并且没有外部参与者会修改它。当函数返回时,它会将返回值的副本传递给调用函数。对象的副本volatile
不是它自己volatile
。因此,尝试返回 avolatile int
将导致复制,将其转换为 non-volatile int
,这就是触发编译器消息的原因。返回 avolatile int*
可能有用,但不是 a volatile int
。
将对象按值传递给函数会生成对象的副本,因此使用 avolatile int
作为函数参数必然涉及忽略限定符的转换。通过地址传递 volatile 是完全合理的,但不是通过值。
根据 C 规范, 的行为volatile
完全依赖于实现,因此 YMMV。
您是否volatile
以这种方式尝试破坏某种编译器优化?如果是这样,可能有更好的方法来做到这一点。
编辑:
考虑到您的问题的更新,您似乎可以以不同的方式解决这个问题。如果您试图阻止编译器优化,为什么不采取直接的方法并简单地告诉编译器不要优化某些东西呢?您可以使用#pragma GCC optimize
或__attribute__((optimize))
为函数提供特定的优化参数。例如,__attribute__((optimize(0)))
应该禁用给定函数的所有优化。这样,您可以使您的数据类型保持非易失性并避免您遇到的类型问题。如果禁用所有优化有点过多,您还可以使用该属性/pragma 打开或关闭单个优化选项。
编辑: 我能够编译以下代码而没有任何警告或错误:
static int functionTwo(int *number) {
return *number + 1;
}
typedef union {
int i;
volatile int v;
} fancy_int;
int main(void) {
fancy_int count;
count.v = 10;
count.v = functionTwo(&count.i);
return 0;
}
这种黑客“技术”可能有一些奇怪的副作用,所以在生产使用之前彻底测试它。这很可能与直接将地址转换为 a 没有什么不同(int*)
,但它不会触发任何警告。
我可能在这里偏离了基础,但 volatile 通常与堆栈内存区域无关。因此,我不确定下面的原型是否真的很有意义。
volatile int functionOne(volatile int number);
我不确定返回的整数如何是易变的。什么会导致 EAX 的值发生变化?这同样适用于整数。一旦值被压入堆栈以便它可以作为参数传递,什么会改变它的值?
我不明白您为什么要volatile
在函数返回类型上使用限定符。您分配函数返回值的变量应volatile
改为 a 类型。
尝试进行以下更改:
typedef int COUNT_TYPE;
typedef volatile COUNT_TYPE COUNT;
COUNT_TYPE functionOne( COUNT number );
COUNT_TYPE functionTwo( COUNT_TYPE number );
调用时functionTwo()
,显式转换参数:
functionTwo( (COUNT_TYPE)arg );
HTH,阿什。
如果我编译
typedef volatile int COUNT;
static int functionTwo(int number) {
return number + 1;
}
int main(void) {
COUNT count = 10;
count = functionTwo(count);
return 0;
}
使用
gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-Wextra -Wstrict-prototypes -Wmissing-prototypes foo.c
我没有收到任何警告。我尝试了 gcc 4.0、4.2、4.3 和 4.4。您的 warningTwo 听起来像是在传递指针,而不是值,这是另一回事...
编辑:
你最新的例子应该这样写;再次,没有警告:
typedef volatile int COUNT;
static int functionTwo(COUNT *number) { return *number + 1; }
int main(void) { COUNT count = 10; count = functionTwo(&count); return 0; }
编辑:
如果你不能改变functionTwo:
typedef volatile int COUNT;
static int functionTwo(int *number) { return *number + 1; }
int main(void) {
COUNT count= 10;
int countcopy = count;
count = functionTwo(&countcopy);
return 0;
}
请注意,对 volatile 变量的任何访问都是“特殊的”。在第一个版本中functionTwo(COUNT *number)
,functionTwo 知道如何正确访问它。在使用 countcopy 的第二个版本中,主函数知道在分配 countcopy = copy 时如何正确访问它。
编写它的人可能想确保所有操作都是原子的,并将所有 int 变量声明为 volatile(它是同步性较差的 MT 应用程序吗?),因此代码中的所有 int 都被声明为 volatile “对于一致性”。
或者,也许通过将函数类型声明为 volatile,他们希望停止对纯函数的重复调用的优化?在函数内部增加一个静态变量可以解决它。但是,试着猜测他们的初衷,因为这根本没有任何意义。