9
4

5 回答 5

9

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*),但它不会触发任何警告。

于 2010-07-21T22:24:08.577 回答
3

我可能在这里偏离了基础,但 volatile 通常与堆栈内存区域无关。因此,我不确定下面的原型是否真的很有意义。

volatile int functionOne(volatile int number);

我不确定返回的整数如何是易变的。什么会导致 EAX 的值发生变化?这同样适用于整数。一旦值被压入堆栈以便它可以作为参数传递,什么会改变它的值?

于 2010-07-21T20:55:35.247 回答
2

我不明白您为什么要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,阿什。

于 2010-07-21T21:52:05.807 回答
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。您的 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 时如何正确访问它。

于 2010-07-21T21:13:08.250 回答
0

编写它的人可能想确保所有操作都是原子的,并将所有 int 变量声明为 volatile(它是同步性较差的 MT 应用程序吗?),因此代码中的所有 int 都被声明为 volatile “对于一致性”。

或者,也许通过将函数类型声明为 volatile,他们希望停止对纯函数的重复调用的优化?在函数内部增加一个静态变量可以解决它。但是,试着猜测他们的初衷,因为这根本没有任何意义。

于 2010-07-21T21:03:49.590 回答