كيفية قراءة من العازلة مع ردود الفعل ، حتى لا تجاوز سعة المخزن المؤقت?

StackOverflow https://stackoverflow.com/questions/2260064

  •  20-09-2019
  •  | 
  •  

سؤال

لدي هذا الكود

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

while ((readcount = sf_read_float(handle, buffer, BUFFER_LEN))) {
  // alsa play
}

الذي يقرأ BUFFER_LEN يطفو من العازلة ، وإرجاع عدد من العوامات ذلك قراءة الواقع."التعامل مع" يقول sf_rad_float كم حجم المخزن المؤقت.

E. g.إذا كان المخزن المؤقت الذي يحتوي على 5 يطفو ، BUFFER_LEN هو 3 ، readcount أن أول عودة 3, و في المرة القادمة 2 ، في حين حلقة من شأنه الخروج.

أود الحصول على وظيفة أن يفعل نفس الشيء.

التحديث

بعد الكثير من الترميز ، وأعتقد أن هذا هو الحل.

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

}

في المرة القادمة copy_buffer() يسمى دست على 3,4.تشغيل copy_buffer() مرة أخرى فقط نسخ القيمة "5".لذلك أعتقد أنه يعمل الآن.

على الرغم من أنها ليست جميلة جدا ، التي لدي int src_pos = 0; خارج على copy_buffer().

فإنه سيكون أفضل بكثير إذا كنت بدلا من ذلك يمكن أن تعطي copy_buffer() فريدة من نوعها بدلا من التعامل مع &src_pos, مثل sndfile لا.

لا أحد يعرف كيف يمكن أن يتم ذلك ؟

هل كانت مفيدة؟

المحلول

إذا كنت ترغب في إنشاء فريدة من نوعها مقابض, يمكنك أن تفعل ذلك مع 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
/*
 * Returns a new traversal handle, or 0 (INVALID_HANDLE) on failure.
 *
 * Allocates memory to contain the traversal state.
 * Resets traversal state to beginning of source buffer.
 */
HANDLE_TYPE init_buffer_traverse(double *src, size_t src_len)
{
    TRAVERSAL * trav = malloc(sizeof(TRAVERSAL));

    if (NULL == trav)
        return INVALID_HANDLE;

    trav->source = src;
    trav->source_len = src_len;
    trav->position = 0;

    return (HANDLE_TYPE)trav;
}
/*
 * Returns the system resources (memory) associated with the traversal handle.
 */
void close_handle_buffer_traverse(HANDLE_TYPE h)
{
    TRAVERSAL * trav = NULL;

    if (INVALID_HANDLE != h)
        free((TRAVERSAL *)h);
}
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;
}

هذا النوع من الاسلوب هو ما بعض ج المبرمجون تستخدم من قبل C++ إلى حيز الوجود.أسلوب ينطوي على بنية بيانات الذي يحتوي على جميع عناصر البيانات لدينا 'الفئة'.معظم API الصف ويأخذ الحجة الأولى ، مؤشر إلى واحدة من هذه البنيات.هذا المؤشر هو مماثل this مؤشر.في مثالنا هذا المعامل كان اسمه trav.

الاستثناء API تلك الأساليب التي تخصص التعامل مع نوع ؛ هذه هي مماثلة لتلك المنشئات يكون التعامل مع نوع قيمة إرجاع.في حالتنا اسمه init_buffer_traverse قد دعا construct_traversal_handle.

هناك العديد من طرق أخرى من هذا الأسلوب في تنفيذ أي "مبهمة تحمل" قيمة.في الواقع, بعض المبرمجون أن التلاعب بت (عن طريق XOR ، على سبيل المثال) من أجل إخفاء الطبيعة الحقيقية مقابض.(هذا الغموض لا توفر الأمن فيها مثل هذه الحاجة.)

في المثال المذكور ، أنا لست متأكدا (لم تنظر sndlib) إذا كان من شأنه أن يجعل معظم معانيها عن المخزن المؤقت الوجهة مؤشر طول سيعقد في التعامل مع هيكل أو لا.إذا كان الأمر كذلك ، من شأنها أن تجعل "نسخة العازلة" التعامل بدلا من "اجتياز" مقبض كنت ترغب في تغيير المصطلحات من هذه الإجابة.

هذه المقابض صالحة فقط من أجل الحياة العملية الحالية ، حتى أنها ليست مناسبة مقابض والتي يجب البقاء على قيد الحياة تشغيل من التعامل مع الخادم.على أن استخدام قاعدة بيانات ISAM العمود ID مقبض.نهج قاعدة البيانات أبطأ بكثير مما كانت عليه في الذاكرة/مؤشر النهج ولكن استمرار مقابض, لا يمكنك استخدام في الذاكرة القيم على أي حال.

ومن ناحية أخرى ، يبدو أنك تنفيذ المكتبة التي سوف تكون قيد التشغيل ضمن عملية واحدة مدى الحياة.في هذه الحالة الجواب لقد كتبت ينبغي أن تكون قابلة للاستخدام بعد تعديل للاحتياجات الخاصة بك.

الإضافة

طلبت بعض التوضيح من التشابه مع C++ التي ذكرت أعلاه.أن تكون محددة, بعض ما يعادلها (إلى فوق رمز C) C++ يمكن أن يكون الكود:

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

هناك بعض الاختلافات الظاهرة.C++ الإصدار هو أقل قليلا مطول-على ما يبدو.بعض من هذا الوهم;أي ما يعادل close_handle_buffer_traverse الآن delete C++ الكائن.بالطبع delete ليست جزءا من الطبقة تنفيذ TRAVERSAL, delete يأتي مع اللغة.

في C++ الإصدار لا يوجد "مبهمة" التعامل معها.

C الإصدار هو أكثر وضوحا وربما يجعل أكثر وضوحا ما هي العمليات التي يتم تنفيذها من قبل الأجهزة ردا على تنفيذ البرنامج.

C الإصدار هو أكثر قابلية استخدام المدلى بها إلى HANDLE_TYPE من أجل خلق "مبهمة ID" بدلا من نوع مؤشر.C++ الإصدار يمكن أن يكون "ملفوفة" في API التي أنجزت الشيء نفسه مع إضافة طبقة أخرى.في التيار سبيل المثال ، يمكن للمستخدمين من هذه الفئة سوف تحافظ على نسخة من TRAVERSAL *, الذي هو ليس تماما "غير شفاف".

في وظيفة copy_buffer(), C++ الإصدار حاجة بي إلى ذكر trav مؤشر لأنه بدلا من ذلك ضمنا dereferences مترجم-الموردة this مؤشر.

sizeof(TRAVERSAL) يجب أن يسري على كل من C و C++ أمثلة-مع أي vtable أيضا افتراض وقت تشغيل-اكتب تعريف عن C++ إيقاف تشغيل C++ class يحتوي فقط على نفس تخطيط الذاكرة مثل C في المثال الأول.

هو أقل شيوعا لاستخدام "مبهمة ID" style in C++, لأن عقوبة "الشفافية" هو lowed في C++.بيانات أعضاء class TRAVERSAL هي private وهكذا TRAVERSAL * لا يمكن أن يكون قصد تستخدم لكسر API لدينا عقد مع API المستخدم.

يرجى ملاحظة أن كلا مبهمة الهوية والطبقة المؤشر هي عرضة للإساءة من الخبيثة API المستخدم إما مبهمة فئة أو معرف مؤشر يمكن أن يلقي مباشرة ، على سبيل المثال ، double **, يسمح صاحب معرف تغيير source الأعضاء مباشرة عبر الذاكرة.بالطبع, يجب أن تثق API المتصل بالفعل ، لأنه في هذه الحالة API استدعاء التعليمات البرمجية في نفس مساحة العنوان.في مثال على ملقم ملفات شبكة اتصال, قد يكون هناك تداعيات أمنية إن "مبهمة ID" استنادا إلى عنوان الذاكرة يتعرض إلى الخارج.

أنا لا عادة جعل الاستطراد في trustedness API المستخدم, ولكن أريد أن أوضح أن C++ الكلمة private لا يوجد لديه "صلاحيات تنفيذية" ، فإنه يحدد اتفاق بين المبرمجين ، والتي مترجم النواحي أيضا إلا إذا قال خلاف ذلك من قبل الإنسان.

وأخيرا فئة C++ مؤشر يمكن تحويلها إلى كامد معرف كما يلي:

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 ولكن للأسف بعد أن تعلمت C++ الأولى.

PS

لقد لاحظت فقط أن لدينا التنفيذ حتى الآن استخدمت:

dest[i] = (float)source[position + i];

عند نسخ بايت.لأن كلا dest و source هي double * (أي أن كلا منهما نقطة double القيم) ، هناك حاجة الزهر هنا.أيضا ، من الصب double إلى float قد تفقد الأرقام من الدقة في تمثيل الفاصلة العائمة.لذلك هذا هو أفضل إزالة كررت مثل:

dest[i] = source[position + i];

نصائح أخرى

بدأت أنظر في ذلك ، ولكن ربما يمكن أن تفعل ذلك فقط كذلك: libsndfile هو المصدر المفتوح ، لذلك يمكن للمرء أن ننظر في كيفية sf_read_float() أعمال إنشاء دالة على أن يفعل الشيء نفسه من المخزن المؤقت. http://www.mega-nerd.com/libsndfile/ لديه رابط التحميل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top