例如,在 32 位处理器的情况下,一个字是 4 字节长。是否也可以使用 5 字节字或其他字?
2 回答
是否也可以使用 5 字节字或其他
是的。您甚至可以通过位字段仅使用几位而不是整个字节/字。从技术上讲,编译器可以支持任何架构上的任何整数大小,例如 16 位计算机上的 12 位、30 位或 96 位 int。事实上,Clang 刚刚为具有任意位宽的整数提供了一个新的扩展,称为_ExtInt
. 也可以看看
为什么不是 40 位或其他数字?
性能会受到很大影响。我们需要更多指令来处理非本地整数大小。如果大小小于一个字,则编译器需要发出按位指令来屏蔽剩余的位。在相反的情况下,我们需要多个指令来处理多个单词
另一个重要的事情是错位。当变量的地址是其大小的倍数或至少是数据总线宽度/字大小的倍数时,现代 CPU 的工作效率更高。使用奇数大小的变量很尴尬
也就是说,存在许多具有 40 位类型的 32 位架构,例如TI C6000或TI C5500 DSP
long
是
- C6000 COFF 为40 位或 5 字节
[...] 并且 C5500 具有40 位
long long
这是因为那些 DSP 有一个特殊的 40 位累加器,允许将 32 位数字相加 256 次而不会溢出。但是为什么不直接使用 64 位累加器呢?这将需要更大的 ALU,需要更多的功率并且运行速度更慢(因为更大的区域意味着硬件组件之间的距离更长,并且在大数字上运行比在较小的数字上运行慢),这在为性能而设计的 DSP 中是不可接受的(可能还有力量)
...例如,德州仪器公司的 TMS320C6000,一个 DSP 处理器,使用 32 位表示类型
int
,使用 40 位表示类型long
(这种选择并不少见)。那些使用 24 位来表示类型的处理器(通常是 DSP)int
,往往使用 48 位来表示类型long
。24/48 位整数类型表示的使用可以由 32/64 位整数类型表示不具成本效益的应用需求驱动。
事实上,40 位 int 在 DSP 中很常见(其他例子是Blackfin和SHARC)。SHARC 甚至有一个 80 位累加器,因此您可以添加大量 64 位值而不必担心溢出
但是您不需要特殊的架构或特殊的编译器支持。如果您确实需要,您仍然可以使用 40 位变量,例如,当您使用一个巨大的数组时,其中 64 位整数会使其太大而无法放入主内存并且更少的项目将适合缓存。最简单的方法是禁用与#pragma pack
或对齐__attribute__((packed))
struct int40_t {
int64_t : 40;
} __attribute__((packed));
int40_t myArray[200] __attribute__((packed));
或从一个简单的 char 数组中访问值(基于cmm 的解决方案)
unsigned char _5byteInts[5*size+3]; // +3 avoids overfetch of last element
int64_t get5byteInt(size_t index)
{
int64_t v = 0;
memcpy(&v, &_5byteInts[index*5], 5); // little endian
return (v << 24) >> 24;
}
void set5byteInt(size_t index, int64_t value)
{
memcpy(&_5byteInts[index*5], &value, 5); // little endian
}
但是这些将导致在没有未对齐访问的架构上性能不佳。您可以将四个 40 位整数打包到一个 20 字节结构中以获得更好的对齐
struct four_int40s {
uint32_t low[4];
uint8_t hi[4];
};
从历史上看,有一些计算机的字长不是 2 的幂,如这个字长表。然而,最终人们发现,当地址大小是 2 的幂时,地址算术更容易实现。
考虑一个操作,例如“向前跳 14 个单词”。如果字长是 2 的幂,比如 64,则电路需要将数字 14 移动log(64)/log(2)=6
并加上ip
,这可以在 1 个周期内轻松完成。但是,如果字长为 36,如 IBM 701,则数字 14 必须乘以 36,这将花费更多周期。鉴于将整数乘以字长是一种非常常见的操作,因此减速将是显着的。