如何在C中定义24位数据类型?

时间:2011-09-14 12:58:49

标签: c

我将不得不使用24位音频数据。这只是unsigned int而不是32bit,它是24bit。那么在C中定义和使用24位数据的简单方法是什么?

7 个答案:

答案 0 :(得分:13)

根据要求,我要么使用位域:

struct int24{
    unsigned int data : 24;
};

或者,如果分离更容易,只需使用3个字节(unsigned char s)。如果你不想填充结构,可以强制打包结构。

[编辑:我看到C++标签已被删除,但我将其留在此处,无论如何] 如果您对C ++更熟悉,可以使用以下内容:

const int INT24_MAX = 8388607;

class Int24
{
protected:
    unsigned char value[3];
public:
    Int24(){}

    Int24( const Int24& val )
    {
        *this   = val;
    }

    operator int() const
    {
        /* Sign extend negative quantities */
        if( value[2] & 0x80 ) {
            return (0xff << 24) | (value[2] << 16)
                                | (value[1] <<  8)
                                |  value[0];
        } else {
            return (value[2] << 16)
                 | (value[1] <<  8)
                 |  value[0];
        }
    }

    Int24& operator= (const Int24& input)
    {
        value[0]   = input.value[0];
        value[1]   = input.value[1];
        value[2]   = input.value[2];

        return *this;
    }

    Int24& operator= (const int input)
    {
        value[0]   = ((unsigned char*)&input)[0];
        value[1]   = ((unsigned char*)&input)[1];
        value[2]   = ((unsigned char*)&input)[2];

        return *this;
    }

    Int24 operator+ (const Int24& val) const
    {
        return Int24( (int)*this + (int)val );
    }

    Int24 operator- (const Int24& val) const
    {
        return Int24( (int)*this - (int)val );
    }

    Int24 operator* (const Int24& val) const
    {
        return Int24( (int)*this * (int)val );
    }

    Int24 operator/ (const Int24& val) const
    {
        return Int24( (int)*this / (int)val );
    }

    Int24& operator+= (const Int24& val)
    {
        *this   = *this + val;
        return *this;
    }

    Int24& operator-= (const Int24& val)
    {
        *this   = *this - val;
        return *this;
    }

    Int24& operator*= (const Int24& val)
    {
        *this   = *this * val;
        return *this;
    }

    Int24& operator/= (const Int24& val)
    {
        *this   = *this / val;
        return *this;
    }

    Int24 operator>> (const int val) const
    {
        return Int24( (int)*this >> val );
    }

    Int24 operator<< (const int val) const
    {
        return Int24( (int)*this << val );
    }

    operator bool() const
    {
        return (int)*this != 0;
    }

    bool operator! () const
    {
        return !((int)*this);
    }

    Int24 operator- ()
    {
        return Int24( -(int)*this );
    }

    bool operator== (const Int24& val) const
    {
        return (int)*this == (int)val;
    }

    bool operator!= (const Int24& val) const
    {
        return (int)*this != (int)val;
    }

    bool operator>= (const Int24& val) const
    {
        return (int)*this >= (int)val;
    }

    bool operator<= (const Int24& val) const
    {
        return (int)*this <= (int)val;
    }

    /* Define all operations you need below.. */

答案 1 :(得分:5)

干净且便携的方式,假设您的样本是小端和无符号的:

static inline uint32_t getsample(uint8_t *buf, size_t pos)
{
    return buf[3*pos] + 256UL*buf[3*pos+1] + 65536UL*buf[3*pos+2];
}

static inline void putsample(uint8_t *buf, size_t pos, uint32_t sample)
{
    buf[3*pos]=sample;
    buf[3*pos+1]=sample/256;
    buf[3*pos+2]=sample/65536;
}

将其修复为有符号值的工作更加有效,特别是如果你想保持它的可移植性。请注意,如果在处理之前将整个样本窗口转换为saner格式,然后在完成后转换回来,性能可能会好得多。

答案 2 :(得分:0)

使用足够大的数据类型来容纳24位数据。这是在{em> stdint.h中定义的int32_tuint32_t

您正在使用音频数据,因此您需要进行额外的工作(您需要进行混音)。还有一些额外的8位可用并不是坏事,因为它为您提供大约24dB的额外动态范围,您需要混合多个充分利用24位动态范围的信号源。

请注意,您只是询问用于24位样本的数据类型。如果您要阅读一个24位样本帧的大量数据流,您必须将其拆分。首先,您必须知道流是 big endian 还是 low endian 。然后你可以使用这样的东西将流重新排列成样本:

uint32_t bitstream_BE_to_sample(uint8_t bits[3])
{
    return (bits[0] << 16) | (bits[1] << 8) | (bits[2]);
}

uint32_t bitstream_LE_to_sample(uint8_t bits[3])
{
    return (bits[2] << 16) | (bits[1] << 8) | (bits[0]);
}

uint8_t *bitstream;
uint32_t *samples;
for(;;) {
    *samples = bitstream_XX_to_sample(bitstream);
    samples++;
    bistream += 3;

    if(end_of_bitstream())
         break;
}

答案 3 :(得分:0)

这些方面的东西:

struct Uint24
{
    unsigned char bits[3]; // assuming char is 8 bits

    Uint24()
        : bits()
    {}

    Uint24(unsigned val) {
        *this = val;
    }

    Uint24& operator=(unsigned val) {
        // store as little-endian
        bits[2] = val >> 16 & 0xff;
        bits[1] = val >> 8 & 0xff;
        bits[0] = val & 0xff;
        return *this;
    }

    unsigned as_unsigned() const {
        return bits[0] | bits[1] << 8 | bits[2] << 16;
    }
};

答案 4 :(得分:-1)

你可以做这样的事情;

union u32to24 {
    unsigned int i;
    char c[3];
};
代码中的

使用u32to24.i来处理值,例如

u32to24 val = //...

val.i += foo
val.i -= bar
// etc

然后输出字符以获得24位

fprintf("%c%c%c",val.c[0],val.c[1],val.c[2]);

Proviso:这是我头脑中的第一件事,因此可能会出现错误,可能会有更好的方法。

答案 5 :(得分:-1)

这项工作对我来说:

typedef unsigned char UInt24[3];

答案 6 :(得分:-1)

我处理有符号和无符号24位整数的方法只是在打包之前和解包之后加/减,如下所示:

void int24_write(uint8_t* bytes, int32_t val)
{
    // Add to make the value positive.
    val += (1 << 23);

    // Make sure the value is in an acceptable range of
    // [-2^23, +2^23).
    assert(val >= 0 && val < (1 << 24));

    // Pack the data from 32-bit to 24-bit.
    bytes[0] = (uint8_t)(val & 0xff);
    bytes[1] = (uint8_t)((val >> 8) & 0xff);
    bytes[2] = (uint8_t)(val >> 16);
}

int32_t int24_read(const uint8_t* bytes)
{
    // Unpack the data from 24-bit to 32-bit.
    return (bytes[0] | (bytes[1] << 8) | (bytes[2] << 16)) - 
           (1 << 23);
}

不确定最佳速度,但它简单且无分支。它可以在以下范围内打包和解包整数:[-2^23, +2^23)。如果有人有关于如何更有效地做到这一点的建议,我会全力以赴。

我倾向于以一种包装数据非常小的方式使用它,平均可能只有3或4个整数(许多小数组从32位压缩到24位或更小),通常我们只有一次打包/解包的3或4个整数,不幸的是随机访问模式来检索这些小的24位数组。也就是说,我确实倾向于一次打包/拆包多次,但又只是一个像3或4这样的小数字,而不是数十或数百或更多。

如果您只需要无符号,那么只需:

void uint24_write(uint8_t* bytes, uint32_t val)
{
    // Make sure the value is in an acceptable range of
    // [0, +2^24).
    assert(val >= 0 && val < (1 << 24));

    // Pack the data from 32-bit to 24-bit.
    bytes[0] = (uint8_t)(val & 0xff);
    bytes[1] = (uint8_t)((val >> 8) & 0xff);
    bytes[2] = (uint8_t)(val >> 16);
}

uint32_t uint24_read(const uint8_t* bytes)
{
    // Unpack the data from 24-bit to 32-bit.
    return (bytes[0] | (bytes[1] << 8) | (bytes[2] << 16));
}

在这种情况下,无符号整数可以在[0, +2^24)范围内。