如何在 C++ 中指定 class 的大小?
How do I specify the size of a class in C++?
我的任务是创建一个实现浮点数的class。
class 的大小必须正好是 3 个字节:
1 位用于符号
6 位指数
17 位尾数
我尝试使用位字段实现 class,但是大小
是 4 个字节:
class FloatingPointNumber
{
private:
unsigned int sign : 1;
unsigned int exponent : 6;
unsigned int mantissa : 17;
};
C++(和 C 就此而言)编译器被允许在他们认为合适的情况下将任意数量的填充插入和附加到 struct
中。因此,如果您的任务指定 必须 恰好是 3 个字节,那么仅使用标准语言元素就无法通过 struct
(或 class
)完成此任务。
使用编译器特定的属性或编译指示,您可以强制编译器不插入填充;然而,对于位域,编译器仍然可能认为需要填补类型对齐要求留下的任何空白。
对于此特定任务,您最好的选择可能是使用这样的 class
class CustomFloat {
protected: // or private: as per @paddy's comment
unsigned char v[3];
}
…并希望编译器不要附加一些填充字节。
万无一失的方法就是
typedef char CustomFloat[3];
并接受,您将无法享受静态类型检查带来的任何好处。
然后对于每个操作使用类型双关的形式将 v
的内容传输到一个(至少 32 位宽)变量中,从那里解压缩位,执行所需的操作,打包位并传输回 v
。例如。像这样:
uint32_t u = 0;
static_assert( sizeof(u) >= sizeof(v) );
memcpy((void*)&u, sizeof(v), (void const*)v);
unsigned sign = (u & SIGN_MASK) >> SIGN_SHIFT;
unsigned mant = (u & MANT_MASK) >> MANT_SHIFT;
unsigned expt = (u & EXPT_MASK) >> EXPT_SHIFT;
// perform operation
u = 0;
u |= (sign << SIGN_SHIFT) & SIGN_MASK;
u |= (mant << MANT_SHIFT) & MANT_MASK;
u |= (expt << EXPT_SHIFT) & EXPT_MASK;
memcpy((void*)v, sizeof(v), (void const*)&u);
是的,这看起来很难看。是的,它非常冗长。但这无论如何都是幕后发生的事情,所以你最好把它写下来。
我的任务是创建一个实现浮点数的class。
class 的大小必须正好是 3 个字节:
1 位用于符号
6 位指数
17 位尾数
我尝试使用位字段实现 class,但是大小 是 4 个字节:
class FloatingPointNumber
{
private:
unsigned int sign : 1;
unsigned int exponent : 6;
unsigned int mantissa : 17;
};
C++(和 C 就此而言)编译器被允许在他们认为合适的情况下将任意数量的填充插入和附加到 struct
中。因此,如果您的任务指定 必须 恰好是 3 个字节,那么仅使用标准语言元素就无法通过 struct
(或 class
)完成此任务。
使用编译器特定的属性或编译指示,您可以强制编译器不插入填充;然而,对于位域,编译器仍然可能认为需要填补类型对齐要求留下的任何空白。
对于此特定任务,您最好的选择可能是使用这样的 class
class CustomFloat {
protected: // or private: as per @paddy's comment
unsigned char v[3];
}
…并希望编译器不要附加一些填充字节。
万无一失的方法就是
typedef char CustomFloat[3];
并接受,您将无法享受静态类型检查带来的任何好处。
然后对于每个操作使用类型双关的形式将 v
的内容传输到一个(至少 32 位宽)变量中,从那里解压缩位,执行所需的操作,打包位并传输回 v
。例如。像这样:
uint32_t u = 0;
static_assert( sizeof(u) >= sizeof(v) );
memcpy((void*)&u, sizeof(v), (void const*)v);
unsigned sign = (u & SIGN_MASK) >> SIGN_SHIFT;
unsigned mant = (u & MANT_MASK) >> MANT_SHIFT;
unsigned expt = (u & EXPT_MASK) >> EXPT_SHIFT;
// perform operation
u = 0;
u |= (sign << SIGN_SHIFT) & SIGN_MASK;
u |= (mant << MANT_SHIFT) & MANT_MASK;
u |= (expt << EXPT_SHIFT) & EXPT_MASK;
memcpy((void*)v, sizeof(v), (void const*)&u);
是的,这看起来很难看。是的,它非常冗长。但这无论如何都是幕后发生的事情,所以你最好把它写下来。