C语言 如何在C中定义24位数据类型?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7416699/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to define 24bit data type in C?
提问by mary
I will have to work a lot with 24-bit audio data. Which is just unsigned int but instead of 32bit, it is 24bit. So what is the easier way to define and work with 24bit data in C?
我将不得不处理 24 位音频数据。这只是无符号整数,但不是 32 位,而是 24 位。那么在 C 中定义和使用 24 位数据的更简单方法是什么?
回答by Michael Foukarakis
Depending on the requirements I'd either use a bitfield for it:
根据要求,我要么为它使用位域:
struct int24{
unsigned int data : 24;
};
Or, if a separation is easier, just use 3 bytes (unsigned chars). You can force the struct to be packed if you don't want it to be padded.
或者,如果分离更容易,只需使用 3 个字节 ( unsigned chars)。如果您不想填充结构,则可以强制将其打包。
[edit: I see the C++tag was removed, but I'm leaving it here regardless]
If you're more comfortable with C++, you can use something like the following:
[编辑:我看到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.. */
回答by R.. GitHub STOP HELPING ICE
The clean and portable way, assuming your samples are little endian and unsigned:
干净和便携的方式,假设你的样本是小端和无符号的:
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;
}
Fixing it up to work for signed values it a little more work, especially if you want to keep it portable. Note that performance might be much better if you convert a whole window of samples to a saner format before processing it, then convert back when you're done.
修复它以适用于带符号的值,它会更有效,特别是如果您想保持它的可移植性。请注意,如果在处理之前将整个样本窗口转换为更合理的格式,然后在完成后转换回来,则性能可能会好得多。
回答by datenwolf
Use a data type that's large enough to hold 24 bits of data. That are int32_tor uint32_tboth defined in stdint.h
使用大到足以容纳 24 位数据的数据类型。这是int32_t或者uint32_t在这两个定义stdint.h
You're working with audio data, so you want addition working (you need it for mixing). Also having some additional 8 bits available is not a bad thing, as it gives you about 24dB of extra dynamic range, which you'll need mixing several sources that make full use of the 24bit dynamic range.
您正在处理音频数据,因此您需要添加工作(您需要它进行混音)。还有一些额外的 8 位可用并不是一件坏事,因为它为您提供了大约 24dB 的额外动态范围,您需要混合多个源以充分利用 24 位动态范围。
Note that you were just asking about a datatype to use for 24 bit samples. If you're going to read a tighly packed stream of 24bit sample frames, you'll have to split that one up. First you must know if the stream is big endianor low endian. Then you can use something like this to rearrange the stream into samples:
请注意,您只是询问用于 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;
}
回答by Maxim Egorushkin
Something along these lines:
沿着这些路线的东西:
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;
}
};
回答by Antony Wong
This work for me:
这对我有用:
typedef unsigned char UInt24[3];
回答by Dragon Energy
The way I do it to handle both signed and unsigned 24-bit integers is just with an addition/subtraction prior to packing and after unpacking, like so:
我处理有符号和无符号 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);
}
Not sure about optimal speed but it's simple and branchless. It can pack and unpack integers in the range: [-2^23, +2^23). If anyone has suggestions on how to do it more efficiently, I'd be all ears.
不确定最佳速度,但它简单且无分支。它可以打包和解包范围内的整数:[-2^23, +2^23)。如果有人对如何更有效地做到这一点有建议,我会全神贯注。
I tend to use it in a way where the data to pack is quite small, maybe just 3 or 4 integers on average (many teeny arrays compressed from 32-bit to 24-bit or smaller), and typically we only have 3 or 4 integers to pack/unpack at a time with unfortunately a random-access pattern to retrieve these small 24-bit arrays. That said I do tend to have multiple to pack/unpack at a time, but again just a small number like 3 or 4, not dozens or hundreds or more.
我倾向于以一种方式使用它,其中要打包的数据非常小,平均可能只有 3 或 4 个整数(许多小数组从 32 位压缩到 24 位或更小),通常我们只有 3 或 4 个一次打包/解包整数,不幸的是随机访问模式来检索这些小的 24 位数组。也就是说,我确实倾向于一次打包/拆包多个,但同样只是少量,例如 3 或 4 个,而不是数十个或数百个或更多。
If you only need unsigned, then simply:
如果您只需要未签名,那么只需:
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));
}
In that case the unsigned integers can be in the range, [0, +2^24).
在这种情况下,无符号整数可以在范围内,[0, +2^24)。
回答by Dan
You could do something like this;
你可以做这样的事情;
union u32to24 {
unsigned int i;
char c[3];
};
in your code maniplate the values using u32to24.ifor example
在您的代码中使用u32to24.i例如操作值
u32to24 val = //...
val.i += foo
val.i -= bar
// etc
then output the chars to get the 24 bits
然后输出字符以获得24位
fprintf("%c%c%c",val.c[0],val.c[1],val.c[2]);
Proviso:this is the first thing to pop into my head thus there may be errors and there may well be better ways of doing this.
附带条件:这是我脑海中浮现的第一件事,因此可能会出现错误,并且很可能有更好的方法来做到这一点。

