拥有此代码:
typedef volatile int COUNT;
COUNT functionOne( COUNT *number );
int functionTwo( int *number );
我无法摆脱一些警告..
我在functionOne prototype
中得到了这个警告1忽略[警告]类型限定符 函数返回类型
我得到这个警告2,无论我用一个COUNT 指针参数调用functionTwo而不是int指针
[警告]丢弃限定符 来自指针目标类型
显然变量/指针不能“强制转换”为volatile / un-volatile ..但是每个参数都必须指定为volatile吗?那么如果已经为非易失性变量定义了库函数怎么用呢?
编辑:使用gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wextra -Wstrict-prototypes -Wmissing-prototypes …
编辑:在Jukka Suomela建议之后,这是警告二的代码示例
typedef volatile int COUNT;
static int functionTwo(int *number) {
return *number + 1;
}
int main(void) {
COUNT count= 10;
count = functionTwo(&count);
return 0;
}
答案 0 :(得分:8)
volatile
关键字旨在应用于表示存储而非功能的对象。从函数返回volatile int
没有多大意义。函数的返回值不会被优化掉(内联函数可能除外,但这是另一种情况......),并且没有外部actor会修改它。当函数返回时,它将返回值的副本传递给调用函数。 volatile
对象的副本本身不是volatile
。因此,尝试返回volatile int
将导致副本,将其转换为非易失性int
,这是触发编译器消息的原因。返回volatile int*
可能很有用,但不是volatile int
。
按值将对象传递给函数会生成对象的副本,因此使用volatile int
作为函数参数必然会涉及忽略限定符的转换。通过地址传递易失性是完全合理的,但不是价值。
根据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;
}
这种 hack “技术”可能有某种奇怪的副作用,所以在生产使用前要彻底测试。将地址直接转换为(int*)
很可能没有什么不同,但它不会触发任何警告。
答案 1 :(得分:3)
我可能会离开这里,但是volatile不是通常与堆栈内存区域相关的东西。因此,我不确定以下原型是否真的有意义。
volatile int functionOne(volatile int number);
我不确定返回的整数是如何变量的。什么会导致EAX的价值发生变化?这同样适用于整数。一旦将值压入堆栈,以便它可以作为参数传递什么将改变它的值?
答案 2 :(得分:2)
如果我编译
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。你的警告两个听起来像是在传递指针,而不是值,这是另一个故事......
修改强>
你最新的例子应该是这样写的;再次,没有警告:
typedef volatile int COUNT;
static int functionTwo(COUNT *number) { return *number + 1; }
int main(void) { COUNT count = 10; count = functionTwo(&count); return 0; }
修改强>
如果你不能改变功能2:
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的第二个版本中,main函数知道在分配countcopy = copy时如何正确访问它。
答案 3 :(得分:2)
我不明白你为什么要在函数返回类型上使用volatile
限定符。您为函数的返回值赋值的变量应该改为volatile
。
尝试进行这些更改:
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, 与Ashish。
答案 4 :(得分:0)
编写它的人可能希望确保所有操作都是原子操作,并将所有int变量声明为volatile(这是一个同步程度较差的MT应用程序吗?),因此代码中的所有内容都声明为挥发性“为了一致性”。
或者也许通过将函数类型声明为volatile,他们希望停止对纯函数的重复调用的优化?函数内部的静态变量的增量将解决它。 但是,试着猜测它们的初衷,因为这没有任何意义。