Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否有更好的方法使用比特流解码文件格式?_C++ - Fatal编程技术网

C++ 是否有更好的方法使用比特流解码文件格式?

C++ 是否有更好的方法使用比特流解码文件格式?,c++,C++,我正在尝试制作一个程序来解码mp3文件(作为练习)。重要的不是它是一个mp3文件,而是文件格式的结构。某些变量的长度(以位为单位)取决于以前的变量。假设一个变量读取2位,根据其值,下一个变量必须读取10位或20位。最糟糕的是,每次连续读取都会被相同的长度抵消 我正在使用下面的实现,它工作得非常好,我对正在生成的asm非常满意 问题在于,此实现需要知道编译期间每个位读取的偏移量和长度。一些变量的可变长度使得它很难实现 有两个想法浮现在我的脑海中,但它们似乎都很糟糕。一种是更改位读取函数,以便将偏移

我正在尝试制作一个程序来解码mp3文件(作为练习)。重要的不是它是一个mp3文件,而是文件格式的结构。某些变量的长度(以位为单位)取决于以前的变量。假设一个变量读取2位,根据其值,下一个变量必须读取10位或20位。最糟糕的是,每次连续读取都会被相同的长度抵消

我正在使用下面的实现,它工作得非常好,我对正在生成的asm非常满意

问题在于,此实现需要知道编译期间每个位读取的偏移量和长度。一些变量的可变长度使得它很难实现

有两个想法浮现在我的脑海中,但它们似乎都很糟糕。一种是更改位读取函数,以便将偏移量作为参数作为常规参数传递给函数,而不是作为模板参数。这显然很糟糕,因为我们失去了美丽的asm。更重要的是,这些信息已经为人所知。当信息在编译时可用时,这不应该发生在运行时。我只需要能够更好地向编译器解释它

另一个想法是使用一些奇怪的模板元编程(检查第二个编码示例)

第一个想法如下:

//该函数的工作原理与我前面提到的位流实现中的函数类似,但偏移量是该函数的参数,而不是模板参数。
模板
uint32读取(整数偏移量,常数uint8*src,uint32累积=0);
uint32_t var1=读取(0,2,数据);
开关(var1){
案例0b00:{
uint32_t var2=读取(2,10,数据);
uint32_t var3=读取(12,3,数据);
uint32_t var4=读取(15,1,数据);
//…等等
打破
}
案例0b01:{
uint32_t var2=读取(2,20,数据);
uint32_t var3=读取(22,3,数据);
uint32_t var4=读取(25,3,数据);
//…等等
打破
}
违约:
打破
}
第二个想法是使用未修改的Read函数,但将所有偏移量和长度移动到sperate模板类,并对每种情况进行专门化

模板结构偏移量和长度{};
结构位读取{无符号偏移量;无符号长度;};
模板结构偏移量和长度{
静态constexpr位读取var2={2,10};
静态constexpr位读取var3={12,3};
静态constexpr位读取var4={15,1};
};
模板结构偏移量和长度{
静态constexpr位读取var2={2,20};
静态constexpr位读取var3={22,3};
静态constexpr位读取var4={25,1};
};
模板
无效多个不同的步骤(uint8_t*数据){
使用偏移量=偏移量和长度;
uint32_t var2=读取(数据);
uint32_t var3=读取(数据);
uint32_t var4=读取(数据);
//…等等
}
uint32_t var1=读取(0,2,数据);
开关(var1){
案例0b00:{
十二种不同的趋势(数据);
打破
}
案例0b01:{
十二种不同的趋势(数据);
打破
}
违约:
打破
}
第二个实现的问题是,我可能会得到另一个长度可能不同的变量。在这一点上,我必须创建4个不同的专门化。下一个是8。。。等等


所以我想最大的问题是:如果我想使用我知道的静态数据,有没有一种合理的方法来对这些格式进行解码?这样生成的asm就会很小。

您可以使用位掩码和shift来执行提取:

int32_t bitmask[2][3] = {
    {
         ?, ?, ?
    },
    {
        ?, ?, ?
    }

};
int32_t shift[2][3] = {
    {
         ?, ?, ?
    },
    {
        ?, ?, ?
    }

};


void extraction(int index, uint32_t follow) {

    uint32_t var2 = (follow & bitmask[index][0]) >> shift[index][0];
    uint32_t var3 = (follow & bitmask[index][1]) >> shift[index][1];
    uint32_t var4 = (follow & bitmask[index][2]) >> shift[index][2];

}


int main()
{
    int32_t v = 0;


    uint32_t var1 = Read(0, 2, data);
    int index = 0;
    switch (var1) {
    case 0b00: {
        uint32_t follow = Read(2, 14, data);
        extraction(0, follow);
        break;
    }

    case 0b01: {
        uint32_t follow = Read(2, 26, data);
        extraction(1, follow);
        break;
    }


}

我不会搜索掩码和shift的所有值,但我可以告诉您如何计算第一个值。你读了(2,10),我们读了14位,所以移位很容易,因为你需要移位4位。二进制掩码为00111111110000 so 0x3FF0。当然,大端和小端可以在这里相互干扰,所以你必须注意数据的顺序是否正确。请注意,为了提高效率,您可以将变量存储在数组中,并将extraction()更改为for循环。

您可以执行两个Read()调用,一个用于14位,另一个用于26位,然后使用位掩码和移位来获取数据。因为您的两个代码是0和1,所以可以将掩码和移位存储在两个数组中,并使用相同的代码执行提取。Yap,这将非常有效。非常感谢你。