从 stdin 读取字节时发生延迟(使用管道)

Delay occurred when reading bytes from stdin (Using pipe)

我正在编写一个 C 程序,它将 sox 的输出作为我程序的输入。通常,我的程序会从 stdin 读取输入,然后进行一些处理。但是,当我从 stdin 读取字节值并将其写回另一个文件(只是为了确保一切正确)时,我看到我的结果是 不知何故被延迟 (这个我不太确定),对比一下原来的(图片是here,上面的波形是sox的命令输出)。

谁能指出我哪里出错了?我已经为这个问题苦苦挣扎了好几个小时。我正在使用 Ubuntu 20.04。谢谢! (如果你想要我的音频文件,here 就是)

生成上述波形的 Sox 命令

cat arctic_a0010.wav | sox -t wav - -b 16 -e signed -t raw - > mid.raw

生成以下波形的命令

cat arctic_a0010.wav | sox -t wav - -b 16 -e signed -t raw - | ./test

我的最小test.c程序

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

void storeValue(short* arr, short* assignValue, long int startPt, long int numBlock) {
    for (long int i = 0; i < numBlock; i++) {
        arr[startPt + i] = assignValue[i];
    }
}

void readFromStdin(short* arr, long* curSize) {
    long r, n = 0;
    int BUFFER_SIZE = 1024;
    short buffer[BUFFER_SIZE];

    freopen(NULL, "rb", stdin);
    while (1) {
        r = fread(buffer, sizeof(short), BUFFER_SIZE, stdin);
        if (r <= 0) {
            break;
        }
        if (n + r > *curSize) {
            *curSize = n + r;
            arr = (short*)realloc(arr, (*curSize) * sizeof(short));
        }
        storeValue(arr, buffer, n, r);
        n = n + r;
    }
}

int main(int argc, char *argv[])
{
    // Read from stdin
    short* inputArray = (short*)malloc(sizeof(short));
    long InpSize = 1, currentIndex = 0;
    readFromStdin(inputArray, &InpSize);

    // Write to file
    FILE *out = fopen("test.raw", "wb");
    fwrite(inputArray, sizeof(short), InpSize, out);
}

C 按值传递参数。这包括指针参数。与所有 by-value 参数一样,在函数作用域内更改值对调用者来说意味着 无意义。如果您想将价值的变化传达给调用者,有多种方法可以做到,最常见的如下所示:


使用那个 Otherwise-Worthless Return 值

现在你的函数 returns void(例如什么都没有)。更改它以将更改的(可能更新的)结果发送到 arr。像这样:

short *readFromStdin(short* arr, long* curSize) {
    long r, n = 0;
    int BUFFER_SIZE = 1024;
    short buffer[BUFFER_SIZE];

    freopen(NULL, "rb", stdin);
    while (1) {
        r = fread(buffer, sizeof(short), BUFFER_SIZE, stdin);
        if (r <= 0) {
            break;
        }
        if (n + r > *curSize) {
            *curSize = n + r;
            arr = realloc(arr, (*curSize) * sizeof *arr);
        }
        storeValue(arr, buffer, n, r);
        n = n + r;
    }

    return arr;
}

并在 main 中:

inputArray = readFromStdin(inputArray, &InpSize);

正式Pointer-To参数通过地址

如果你想改变实参,你需要记住C是pass-by-value。因此,您需要设置参数以接受要更改的 'thing' 的地址,并将该地址作为正式参数传递到调用站点。即使是最新手的 C 程序员也熟悉简单的整数交换:

#include <stdio.h>

void swap_int(int *pa, int *pb)
{
    int tmp = *pa;
    *pa = *pb;
    *pb = tmp;
}

int main()
{
    int a = 1, b = 2;
    swap_int(&a,&b);
    printf("%d %d\n", a, b);
}

请注意,这会更改存储在 abmain 中的值,因为它们的地址用作 pointer-type 形式参数的参数,并且取消引用允许我们之后将数据写入其中。

现在,考虑一下:

void make_me_bigger(int *arr, int *size)
{
    *size += 10;
    arr = realloc(arr, *size * sizeof *arr);
}

arr = 没有取消引用,与此

没有什么不同
int foo(int x)
{
    x = 20; // only changes x locally
}

main

调用 foo
int main()
{
    int x = 10;
    foo(x);
    printf("%d\n", x); // still 10
}

如果你想通过“引用”传递一些东西,方法是将形参声明为pointer-to-type(其中'type'是底层数据类型),并通过你的 var 的地址,就像我们在上面 swap_int.

中所做的一样

这是真的,即使参数已经是指针类型。在那些情况下,形式参数变为指向 pointer-to-type 的指针,而来自调用站点的参数是指针变量的地址

换句话说,终于:

void readFromStdin(short **arr, long* curSize) {
    long r, n = 0;
    int BUFFER_SIZE = 1024;
    short buffer[BUFFER_SIZE];

    freopen(NULL, "rb", stdin);
    while (1) {
        r = fread(buffer, sizeof(short), BUFFER_SIZE, stdin);
        if (r <= 0) {
            break;
        }
        if (n + r > *curSize) {
            *curSize = n + r;
            *arr = realloc(*arr, (*curSize) * sizeof **arr);
        }
        storeValue(*arr, buffer, n, r);
        n = n + r;
    }
}

过多的其他事情(不检查您的 realloc 结果、转换 malloc 等)都是额外修复的燃料,但主要问题可以通过上述任一技术解决。