2014-06-14 99 views
-2

我试图做一个通用的循环缓冲区使用无效指针缓冲区,我得到一些问题,我不明白。无效指针铸造到一些其他指针类型T不像T

如果我为我的缓冲区使用了一个双指针,我的循环缓冲区的行为与预期相同(请参阅下面的test1),但是如果我使用void指针,我会得到一个错误的行为(请参阅test2),尽管所有void指针都是铸造双重指针。我的演员有什么问题?

还有一个问题:在circular_buffer_write_chunk我使用双指针来传递数据。我需要通过它作为一个空指针,以使其通用。然后,我必须在函数中动态地将其转换为缓冲区的类型(可能为doubleint),以便使指针运算起作用。我怎样才能做到这一点?我如何获得指向缓冲区的指针的类型,然后将我的数据指针转换为该类型?

欢迎任何评论或建议。

TEST1运行circular_buffer_test()用缓冲液作为双指针

*** circular_buffer test*** 
capacity: 12 

Write 5 values 
cb[0]=0.000000 
cb[1]=1.000000 
cb[2]=2.000000 
cb[3]=3.000000 
cb[4]=4.000000 
cb[5]=0.000000 
cb[6]=0.000000 
cb[7]=0.000000 
cb[8]=0.000000 
cb[9]=0.000000 
cb[10]=0.000000 
cb[11]=0.000000 

Write 10 values 
cb[0]=12.000000 
cb[1]=13.000000 
cb[2]=14.000000 
cb[3]=3.000000 
cb[4]=4.000000 
cb[5]=5.000000 
cb[6]=6.000000 
cb[7]=7.000000 
cb[8]=8.000000 
cb[9]=9.000000 
cb[10]=10.000000 
cb[11]=11.000000 

Test done 

TEST2用缓冲液为空指针运行circular_buffer_test()。为什么这是不同的?

*** circular_buffer test*** 
capacity: 12 

Write 5 values 
cb[0]=0.000000 
cb[1]=1.000000 
cb[2]=2.000000 
cb[3]=3.000000 
cb[4]=4.000000 
cb[5]=0.000000 
cb[6]=0.000000 
cb[7]=0.000000 
cb[8]=0.000000 
cb[9]=0.000000 
cb[10]=0.000000 
cb[11]=0.000000 

Write 10 values 
cb[0]=12.000000 
cb[1]=13.000000 
cb[2]=14.000000 
cb[3]=0.000000 // ? 
cb[4]=0.000000 // ? 
cb[5]=0.000000 // ? 
cb[6]=0.000000 // ? 
cb[7]=0.000000 // ? 
cb[8]=0.000000 // ? 
cb[9]=0.000000 // ? 
cb[10]=0.000000 // ? 
cb[11]=0.000000 // ? 

Test done 

circular_buffer.c

#include "circular_buffer.h" 

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

typedef struct 
{ 
    double *buffer; 
    double *buffer_end; 
    unsigned int capacity; 
    double *read_ptr; 
    double *write_ptr; 
    unsigned int count; 
} circular_buffer; 

/* 

// Why doesn't this behave like with double pointer, since it's casted in circular_buffer_init_double? 

typedef struct 
{ 
    void *buffer; 
    void *buffer_end; 
    unsigned int capacity; 
    void *read_ptr; 
    void *write_ptr; 
    unsigned int count; 
} circular_buffer; 

*/ 

void circular_buffer_init_double(circular_buffer *cb, unsigned int capacity) 
{ 
    cb->buffer = (double*) malloc(sizeof(double) * capacity); 
    cb->buffer_end = (double*) (cb->buffer + capacity); 
    cb->capacity = capacity; 
    cb->read_ptr = (double*) (cb->buffer); 
    cb->write_ptr = (double*) (cb->buffer); 
    cb->count = 0; 
} 

void circular_buffer_destroy(circular_buffer *cb){ 
    free(cb->buffer); 
    cb->buffer = NULL; 
} 

int circular_buffer_is_full(circular_buffer *cb) { 
    return cb->count == cb->capacity; 
} 

int circular_buffer_is_empty(circular_buffer *cb) { 
    return cb->count == 0; 
} 

unsigned int circular_buffer_write_chunk(circular_buffer* cb, double *data, unsigned int type_size, 
    unsigned int num_elements){ 

    if(num_elements > cb->capacity) return 0; 

    if(cb->write_ptr + num_elements > cb->buffer_end){ 

    unsigned int write_ptr_to_buffer_end = cb->buffer_end - cb->write_ptr; 
    unsigned int write_ptr_position = cb->write_ptr - cb->buffer; 

    memcpy(cb->write_ptr, data, write_ptr_to_buffer_end * type_size); 
    memcpy(cb->buffer, data + write_ptr_to_buffer_end, 
     (num_elements - write_ptr_to_buffer_end) * type_size); 
    cb->write_ptr = cb->buffer + num_elements - write_ptr_to_buffer_end; 
    } 
    else{ 
    memcpy(cb->write_ptr, data, type_size * num_elements); 
    cb->write_ptr += num_elements; 
    if(cb->write_ptr == cb->buffer_end){ 
     cb->write_ptr = cb->buffer; 
    } 
    } 

    if(circular_buffer_is_full(cb)) cb->read_ptr = cb->write_ptr; 

    cb->count = cb->count + num_elements > cb->capacity ? cb->capacity : cb->count + num_elements; 

    return num_elements; 
} 

void circular_buffer_test(){ 

    fprintf(stdout, "*** circular_buffer test***\n"); 

    circular_buffer *cb = malloc(sizeof(circular_buffer)); 
    circular_buffer_init_double(cb, 12); 
    fprintf(stdout, "capacity: %d\n", cb->capacity); 

    int i; 
    double *w1 = malloc(sizeof(double) * 5); 
    for(i=0; i<5; i++) w1[i] = (double) i; 

    fprintf(stdout, "\nWrite 5 values\n"); 
    circular_buffer_write_chunk(cb, w1, sizeof(double), 5); 
    for(i=0; i<12; i++) fprintf(stdout, "cb[%d]=%f\n", i, ((double *)cb->buffer)[i]); 

    fprintf(stdout, "\nWrite 10 values\n"); 
    double *w2 = malloc(sizeof(double) * 10); 
    for(i=5; i<15; i++) w2[i-5] = (double) i; 
    circular_buffer_write_chunk(cb, w2, sizeof(double), 10); 
    for(i=0; i<12; i++) fprintf(stdout, "cb[%d]=%f\n", i, ((double *)cb->buffer)[i]); 

    free(w1); 
    free(w2); 

    circular_buffer_destroy(cb); 

    fprintf(stdout, "Test done\n"); 
} 
+1

要求人们发现代码中的错误并不是特别有效。您应该使用调试器(或者添加打印语句)来分析问题,追踪程序的进度,并将其与预期发生的情况进行比较。只要两者发生分歧,那么你就发现了你的问题。 (然后如果有必要的话,你应该构造一个[最小测试用例](http://stackoverflow.com/help/mcve)。) –

+0

@OliCharlesworth我确实花了一些时间试图理解发生了什么,我不能弄清楚,这就是为什么我问。我想这是与该演员有关的事情,但我不明白为什么。 – jul

回答

2

void *指针运算不是在C允许:

(double*) (cb->buffer + capacity); 

gcc通过考虑的尺寸增加了指针运算为void *作为扩展void1

无论buffervoid *gccdouble *cb->buffer + capacity结果将是不同的。使用:

 ((double*) cb->buffer + capacity); 

if buffer is void *

+0

@jul指针的算术运算是用'buffer'成员声明的类型完成的(在'circular_buffer'声明中'void *'或'double *')。 'malloc'后的'double *'强制转换实际上是无用的,可以被删除(或*应该被删除,参见http://c-faq.com/malloc/cast.html)。 – ouah

+0

我知道'void *'不允许使用指针算术(这也是为什么我想知道如何在我的第二个问题中使用'void *'来强制转换数据),但不是缓冲区指针不是void在这一点上,因为它在上面的行中被赋值为double *:'cb-> buffer =(double *)malloc(sizeof(double)* capacity);'? – jul

+0

但是当使用通用'void *'缓冲区时,我确实想在'circular_buffer_init_double'中强制转换为'double *',以便我的指针运算起作用。我不能那样做? – jul