指向易失性结构的不透明指针
Opaque pointer to volatile struct
我在我的嵌入式 C 程序中使用了一个简单的 FIFO 环形缓冲区队列(使用 TI C28x C/C++ 编译器,它与没有扩展的 C89 的 GCC 非常相似)。
数据从中断中与队列一起推送和弹出,因此队列需要是易变的。
我已经实现了队列代码本身 没有 使用 volatile 以便队列用户可以选择队列是否是 volatile (我想在多个队列中使用它具有不同用途的项目),通过在使用中将句柄声明为易失性队列对象,而不是在实现中将队列对象本身定义为易失性。
即在 que.c:
struct QUE_Obj { /* Object & members are not defined as volatile. */
void * data;
uint16_t capacity;
uint16_t head;
uint16_t tail;
uint16_t size;
bool full;
bool empty;
}
/* Implementation uses all non-volatile types. */
QUE_Handle QUE_init(void * data, uint_least8_t size, uint16_t capacity) {
/* ... */
QUE_Handle q = (QUE_Handle)malloc(sizeof(struct QUE_Obj));
/* ... */
return q;
}
/* ... */
在queue.h中:
typedef QUE_Obj * QUE_Handle;
QUE_Handle QUE_init(void * data, uint_least8_t size, uint16_t capacity)
在main.c中:
/* Data buffer and queue handle declared to be for volatile data. */
static volatile uint16_t buffer[BUFFER_LENGTH] = {0};
volatile QUE_Handle que = QUE_init((void *)buffer); /* Buffer passed without volatile. */
然后我的问题是,在 C 语言的最后一行,当我将缓冲区转换为 void *
时,这是否消除了波动率的任何用处?
我是否应该将 QUE_Obj
的成员定义为始终可变的,并将实现中使用的类型调整为可变的,而不管队列的用途如何?
换个方式问,push()
和 pop()
函数是从中断服务例程中调用的,但是它们的实现没有 "know" 关于波动性,它们会被优化掉吗?
您不应通过非易失性指针访问易失性数据。考虑以下简单示例:
volatile int volatileVar;
int* nonVolatilePtr = &volatileVar;
每当您的代码通过 nonVolatilePtr
访问 volatileVar
时,编译器 不会 知道您正在访问的数据是易变的,并且可能会优化对它(这显然是一种不受欢迎的行为)。我很少看到使用非易失性指针指向易失性数据。
如果您希望您的队列可能被中断服务程序(或类似程序)访问,我会让整个数据结构可变。
我在我的嵌入式 C 程序中使用了一个简单的 FIFO 环形缓冲区队列(使用 TI C28x C/C++ 编译器,它与没有扩展的 C89 的 GCC 非常相似)。 数据从中断中与队列一起推送和弹出,因此队列需要是易变的。
我已经实现了队列代码本身 没有 使用 volatile 以便队列用户可以选择队列是否是 volatile (我想在多个队列中使用它具有不同用途的项目),通过在使用中将句柄声明为易失性队列对象,而不是在实现中将队列对象本身定义为易失性。
即在 que.c:
struct QUE_Obj { /* Object & members are not defined as volatile. */
void * data;
uint16_t capacity;
uint16_t head;
uint16_t tail;
uint16_t size;
bool full;
bool empty;
}
/* Implementation uses all non-volatile types. */
QUE_Handle QUE_init(void * data, uint_least8_t size, uint16_t capacity) {
/* ... */
QUE_Handle q = (QUE_Handle)malloc(sizeof(struct QUE_Obj));
/* ... */
return q;
}
/* ... */
在queue.h中:
typedef QUE_Obj * QUE_Handle;
QUE_Handle QUE_init(void * data, uint_least8_t size, uint16_t capacity)
在main.c中:
/* Data buffer and queue handle declared to be for volatile data. */
static volatile uint16_t buffer[BUFFER_LENGTH] = {0};
volatile QUE_Handle que = QUE_init((void *)buffer); /* Buffer passed without volatile. */
然后我的问题是,在 C 语言的最后一行,当我将缓冲区转换为 void *
时,这是否消除了波动率的任何用处?
我是否应该将 QUE_Obj
的成员定义为始终可变的,并将实现中使用的类型调整为可变的,而不管队列的用途如何?
换个方式问,push()
和 pop()
函数是从中断服务例程中调用的,但是它们的实现没有 "know" 关于波动性,它们会被优化掉吗?
您不应通过非易失性指针访问易失性数据。考虑以下简单示例:
volatile int volatileVar;
int* nonVolatilePtr = &volatileVar;
每当您的代码通过 nonVolatilePtr
访问 volatileVar
时,编译器 不会 知道您正在访问的数据是易变的,并且可能会优化对它(这显然是一种不受欢迎的行为)。我很少看到使用非易失性指针指向易失性数据。
如果您希望您的队列可能被中断服务程序(或类似程序)访问,我会让整个数据结构可变。