volatile变量作为函数的参数

时间:2010-07-21 20:44:15

标签: c pointers arguments warnings volatile

拥有此代码:

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;
}

5 个答案:

答案 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,他们希望停止对纯函数的重复调用的优化?函数内部的静态变量的增量将解决它。 但是,试着猜测它们的初衷,因为这没有任何意义。