在c ++中定义可容纳六个值的最小可能数据类型

时间:2009-04-11 14:50:34

标签: c++ memory binary memory-management hex

我想定义自己的数据类型,它可以包含六个可能值中的一个,以便在c ++中了解有关内存管理的更多信息。在数字中,我希望能够保持0到5.二进制,只需要三位(101 = 5)即可,但有些(6和7)不会被使用。数据类型也应该消耗尽可能少的内存。

我不确定如何做到这一点。首先,我尝试了一个枚举,其中包含所有字段的已定义值。据我所知,这里的值是十六进制的,所以一个“hexbit”应该允许我存储0到15.但是将它与char(与sizeof)进行比较,它表示它是char的4倍大小,并且如果我没有误解,则char保持0到255。

#include <iostream>

enum Foo
{
    a = 0x0, 
    b = 0x1,
    c = 0x2,
    d = 0x3,
    e = 0x4,
    f = 0x5,
};

int main()
{
    Foo myfoo = a;
    char mychar = 'a';

    std::cout << sizeof(myfoo); // prints 4
    std::cout << sizeof(mychar); // prints 1

    return 1;
}

我明显误解了一些事情,但没有看到什么,所以我转向了SO。 :)

另外,在写这篇文章时,我意识到我显然缺少词汇的某些部分。我把这篇文章作为一个社区维基,请编辑它,以便我可以为所有内容学习正确的单词。

10 个答案:

答案 0 :(得分:7)

char是最小的类型。

如果您碰巧知道在一个地方需要几个这样的3位值,那么您将使用具有位域语法的结构:

struct foo {
  unsigned int val1:3;
  unsigned int val2:3;
};

因此在一个字节内得到2个。从理论上讲,你可以将10个这样的字段打包成32位的“int”值。

答案 1 :(得分:3)

C ++ 0x将包含Strongly typed enumerations,您可以在其中指定基础数据类型(在示例中为char),但当前的C ++不支持此类型。标准在这里不清楚char的使用(示例有int,short和long),但是他们提到了底层整数类型,并且还包括char。

截至今天,Neil Butterworth为您的问题创建类的答案似乎是最优雅的,因为如果您想要值的符号名称,您甚至可以扩展它以包含嵌套枚举。

答案 2 :(得分:2)

C ++不表示小于字节的内存单位。如果你一次生产一个,这是你能做的最好的。你自己的例子效果很好。如果您需要获得一些,您可以使用位字段,如Alnitak建议的那样。如果你打算一次分配一个,那你就更糟了。大多数archetectures分配页面大小单位,16个字节是常见的。

另一种选择可能是将std :: bitset包装起来进行出价。如果你需要很多这样的值,那么这将浪费很少的空间,每8个只有大约1位。

如果您将问题视为以base-6表示的数字,并将该数字转换为基数2,可能使用无限制的精度整数(例如GMP),则不会浪费任何位数。< / p>

当然,这假定您的值具有统一的随机分布。如果他们遵循不同的发行版,你最好的选择是第一个例子的一般压缩,比如gzip。

答案 3 :(得分:1)

您可以使用的最小尺寸 - 1个字节。

但是如果你使用一组枚举值(写入文件或存储在容器中,......),你可以打包这个组 - 每个值3位。

答案 4 :(得分:1)

最好的解决方案是创建使用char实现的自己的类型。这应该有sizeof(MyType)== 1,但这不能保证。

#include <iostream>
using namespace std;

class MyType {

    public:

        MyType( int a ) : val( a ) {
            if ( val < 0 || val > 6 ) {
                throw( "bad value" );
            }
        }

        int Value() const {
            return val;
        }

    private:

        char val;
};

int main() {

    MyType v( 2 );
    cout << sizeof(v) << endl;
    cout << v.Value() << endl;
}

答案 5 :(得分:1)

您不必枚举枚举值:

enum Foo
{
    a, 
    b,
    c,
    d,
    e,
    f,
};
Foo myfoo = a;

此处Fooint的别名,在您的计算机上占用4个字节。

最小的类型是char,它被定义为目标机器上的最小可寻址数据。 CHAR_BIT宏会产生char中的位数,并在limits.h中定义。

[编辑]

请注意,一般来说,您不应该问自己这样的问题。如果足够,请始终使用[unsigned] int,除非您分配了大量内存(例如int[100*1024]char[100*1024],但请考虑使用std::vector)。

答案 6 :(得分:1)

您可以存储小于8位或32位的值。您只需将它们打包到结构(或类)中并使用bit fields

例如:

struct example
{
    unsigned int a : 3; //<Three bits, can be 0 through 7.
            bool b : 1; //<One bit, the stores 0 or 1.
    unsigned int c : 10; //<Ten bits, can be 0 through 1023.
    unsigned int d : 19; //<19 bits, can be 0 through 524287.
}

在大多数情况下,您的编译器会在32位平台上将结构的总大小向上舍入为32位。另一个问题是,正如您所指出的那样,您的值可能没有两个范围的幂。这将浪费空间。如果您将整个结构读作一个数字,如果您的输入范围不是2的全部幂,您将找到无法设置的值。

您可能感兴趣的另一个功能是union。它们像结构一样工作,但共享内存。因此,如果你写一个字段,它会覆盖其他字段。

现在,如果你对空间非常紧张,并且想要将每个位推到最大,那么就有一种简单的编码方法。假设你想要存储3个数字,每个数字可以是0到5.比特字段是浪费的,因为如果你每个使用3比特,你会浪费一些值(即你有可能永远不会设置6或7,即使你有存放它们的空间)。所以,让我们举个例子:

//Here are three example values, each can be from 0 to 5:
const int one = 3, two = 4, three = 5;

为了最有效地将它们打包在一起,我们应该在基数6中思考(因为每个值都是0-5)。因此,填入最小的空间是:

//This packs all the values into one int, from 0 - 215.
//pack could be any value from 0 - 215. There are no 'wasted' numbers.
int pack = one + (6 * two) + (6 * 6 * three);

看看我们是如何编码基数为六的?每个数字乘以它的位置,如6 ^ n,其中n是地方(从0开始)。

然后解码:

const int one = pack % 6;
pack /= 6;
const int two = pack % 6;
pack /= 6;
const int three = pack;

当您必须对条形码或字母数字序列中的某些字段进行编码以进行人类输入时,这些方案非常方便。只是说那些少数部分可以产生巨大的差异。此外,字段不必都具有相同的范围。如果一个字段是从0到7,则在适当的位置使用8而不是6。不要求所有字段都具有相同的范围。

答案 7 :(得分:1)

由于架构不支持位级操作(因此每次操作需要多个处理器指令),将奇数大小的值打包到位域中可能会导致相当大的性能损失。在实现这样一种类型之前,问问自己是否真的必须使用尽可能少的空间,或者如果你承诺编程的主要原因是过早优化。至多,我会将值封装在一个类中,如果你真的需要因为某些原因需要挤压每个最后一个字节,那么它的后备存储可以透明地改变。

答案 8 :(得分:0)

您可以使用unsigned char。可能会将其输入到BYTE中。它只占用一个字节。

答案 9 :(得分:0)

枚举的大小定义为与int相同。但是根据您的编译器,您可以选择创建较小的枚举。例如,在GCC中,您可以声明:

enum Foo {
    a, b, c, d, e, f
}
__attribute__((__packed__));

现在,sizeof(Foo)== 1。