C 如何通过反馈从缓冲区读取,因此';缓冲区溢出?

C 如何通过反馈从缓冲区读取,因此';缓冲区溢出?,c,buffer-overflow,C,Buffer Overflow,我有这个密码 #define BUFFER_LEN (2048) static float buffer[BUFFER_LEN]; int readcount; while ((readcount = sf_read_float(handle, buffer, BUFFER_LEN))) { // alsa play } 它从缓冲区读取缓冲区浮点数,并返回实际读取的浮点数。“句柄”告诉sf_rad_float缓冲区有多大 例如,如果缓冲区包含5个浮点数,且缓冲区长度为3,readcoun

我有这个密码

#define BUFFER_LEN (2048)
static float buffer[BUFFER_LEN];
int readcount;

while ((readcount = sf_read_float(handle, buffer, BUFFER_LEN))) {
  // alsa play
}
它从缓冲区读取缓冲区浮点数,并返回实际读取的浮点数。“句柄”告诉sf_rad_float缓冲区有多大

例如,如果缓冲区包含5个浮点数,且缓冲区长度为3,readcount将首先返回3,下一次返回2,while循环将退出

我想有一个函数,做同样的事情

更新

经过大量的编码,我认为这就是解决方案

#include <stdio.h>

int copy_buffer(double* src, int src_length, int* src_pos,
                float* dest, int dest_length) {

  int copy_length = 0;

  if (src_length - *src_pos > dest_length) {
    copy_length = dest_length;
    printf("copy_length1 %i\n", copy_length);
  } else {
    copy_length = src_length - *src_pos;
    printf("copy_length2 %i\n", copy_length);
  }

  for (int i = 0; i < copy_length; i++) {
    dest[i] = (float) src[*src_pos + i];
  }

  // remember where to continue next time the copy_buffer() is called
  *src_pos += copy_length;

  return copy_length;
}

int main() {

  double src[] = {1,2,3,4,5};
  int src_length = 5;

  float dest[] = {0,0};
  int dest_length = 2;

  int read;
  int src_pos = 0;
  read = copy_buffer(src, src_length, &src_pos, dest, dest_length);
  printf("read %i\n", read);
  printf("src_pos %i\n", src_pos);

  for (int i = 0; i < src_length; i++) {
    printf("src %f\n", src[i]);
  }

  for (int i = 0; i < dest_length; i++) {
    printf("dest %f\n", dest[i]);
  }

  return 0;

}
#包括
int copy_缓冲区(双*src,int src_长度,int*src_位置,
浮动*dest,int dest_长度){
int copy_length=0;
if(src_长度-*src_位置>目的地长度){
复制长度=目的地长度;
printf(“复制长度1%i\n”,复制长度);
}否则{
复制长度=src长度-*src位置;
printf(“复制长度2%i\n”,复制长度);
}
对于(int i=0;i
下次调用copy_buffer()时,dest包含3,4。再次运行
copy\u buffer()
仅复制值“5”。所以我认为它现在起作用了

虽然它不是很漂亮,但是我有
intsrc_pos=0外部打开
复制缓冲区()

如果我能给
copy\u buffer()
一个唯一的句柄,而不是像sndfile那样给
&src\u pos
,那会好得多


有人知道如何做到这一点吗?

我开始研究它,但你可能也可以这么做:libsndfile是开源的,所以你可以看看
sf\u read\u float()
是如何工作的,并创建一个从缓冲区执行相同操作的函数。有一个下载链接。

如果要创建唯一句柄,可以使用
malloc()
struct

typedef intptr_t HANDLE_TYPE; HANDLE_TYPE init_buffer_traverse(double * src, size_t src_len); int copy_buffer(HANDLE_TYPE h_traverse, double * dest, size_t dest_len); void close_handle_buffer_traverse(HANDLE_TYPE h); typedef struct { double * source; size_t source_length; size_t position; } TRAVERSAL; #define INVALID_HANDLE 0 有一些明显的区别。C++版本看起来有点冗长。其中一些是虚幻的;C++的对象等价于当然,
delete
不是
TRAVERSAL
类实现的一部分,
delete
与该语言一起提供

在C++版本中,没有“不透明”句柄。 C版本更加明确,并且可能使硬件在响应程序执行时执行的操作更加明显

C版本更易于使用cast to
HANDLE_TYPE
来创建“不透明ID”,而不是指针类型。C++版本可以“打包”在API中,在添加另一层时,实现相同的API。在当前示例中,该类的用户将维护一个
遍历*
的副本,该副本不太“不透明”

在函数<代码> CopyBuffel()/Cuff>中,C++版本不必提及<代码> TRAV < /Cult>指针,因为它隐含地取消了编译器提供的<代码> < <代码>指针> < /P> > SigeOf(TraceOver)/Cux>对于C和C++示例都应该是相同的——没有VTABLE,也假设C++运行时类型标识被关闭,C++类只包含与我们第一个例子中的C结构相同的内存布局。 <> >在C++中使用“不透明ID”样式较不常见,因为C++中“透明度”的惩罚被降低。

类遍历
的数据成员是
私有的
,因此
遍历*
不能意外地用于破坏我们与API用户的API合同

请注意,不透明ID和类指针都容易被恶意API用户滥用——不透明ID或类指针都可以直接强制转换到,例如,
double**
,允许ID持有者通过内存直接更改
成员。当然,您必须已经信任API调用方,因为在这种情况下,API调用代码位于相同的地址空间中。在网络文件服务器的示例中,如果将基于内存地址的“不透明ID”暴露给外部,则可能存在安全隐患

我通常不会把API转换成信任度,但是我想澄清C++关键字>代码>私有< /C>没有“强制力”,它只规定程序员之间的一个协议,编译器也尊重它,除非人类告诉它。

最后,C++类指针可以转换为不透明的ID:

typedef intptr_t HANDLE_TYPE;

HANDLE_TYPE init_buffer_traverse(double *src, size_t src_len)
{
    return (HANDLE_TYPE)(new TRAVERSAL(src, src_len));
}

int copy_buffer(HANDLE_TYPE h_traverse, double * dest, size_t dest_len)
{
    return ((TRAVERSAL *)h_traverse)->copy_buffer(dest, dest_len);
}

void close_handle_buffer_traverse(HANDLE_TYPE h)
{
    delete ((TRAVERSAL *)h);
}
现在我们对“等价”C++的简洁性可能会受到进一步质疑。 我写的关于C++编程的旧风格并不是说C++更适合这个任务。我只是说,封装数据和隐藏实现细节可以通过C语言来完成,它的风格几乎与C++风格同构。如果你发现自己在C中编程,但很遗憾,首先学习C++,这是很好的。 PS

我刚刚注意到,到目前为止,我们的实施使用了:

dest[i] = (float)source[position + i];
当复制字节时。因为
dest
source
都是
double*
(也就是说,它们都指向
double
值),所以这里不需要强制转换。此外,从
double
float
的转换可能会丢失浮点表示中的精度位数。所以这是最好的选择 int copy_buffer(HANDLE_TYPE h, float* dest, int dest_length) { TRAVERSAL * trav = NULL; if (INVALID_HANDLE == h) return -1; trav = (TRAVERSAL *)h; int copy_length = trav->source_length - trav->position; if (dest_length < copy_length) copy_length = dest_length; for (int i = 0; i*emphasized text* < copy_length; i++) dest[i] = trav->source[trav->position + i]; // remember where to continue next time the copy_buffer() is called trav->position += copy_length; return copy_length; }
class TRAVERSAL
{
    double * source;
    size_t source_length;
    size_t position;

    public TRAVERSAL(double *src, size_t src_len)
    {
        source = src;
        source_length = src_len;
        position = 0;
    }

    public int copy_buffer(double * dest, size_t dest_len)
    {
        int copy_length = source_length - position;
        if (dest_length < copy_length)
            copy_length = dest_length;

        for (int i = 0; i < copy_length; i++)
            dest[i] = source[position + i];

        // remember where to continue next time the copy_buffer() is called
        position += copy_length;

        return copy_length;            
    }
}
typedef intptr_t HANDLE_TYPE;

HANDLE_TYPE init_buffer_traverse(double *src, size_t src_len)
{
    return (HANDLE_TYPE)(new TRAVERSAL(src, src_len));
}

int copy_buffer(HANDLE_TYPE h_traverse, double * dest, size_t dest_len)
{
    return ((TRAVERSAL *)h_traverse)->copy_buffer(dest, dest_len);
}

void close_handle_buffer_traverse(HANDLE_TYPE h)
{
    delete ((TRAVERSAL *)h);
}
dest[i] = (float)source[position + i];
dest[i] = source[position + i];