当前位置: 首页 > 知识库问答 >
问题:

为什么类型总是一个特定的大小,不管它的值?

公良征
2023-03-14
int myInt = 255;

共有1个答案

苏野
2023-03-14

编译器应该为某些机器生成汇编程序(并最终生成机器代码),通常C++会尝试与该机器保持一致。

对底层机器的同情大致上意味着:使编写C++代码变得容易,这些代码将有效地映射到机器可以快速执行的操作上。因此,我们希望在硬件平台上提供对快速和“自然”的数据类型和操作的访问。

具体地说,考虑一个特定的机器体系结构。就拿目前的英特尔x86家族来说吧。

因此,我们希望编译器在编译简单的C++整数运算时使用这些EAX、EBX等寄存器。这意味着当我声明一个int时,它应该是与这些寄存器兼容的东西,这样我就可以高效地使用它们。

寄存器的大小总是相同的(这里是32位),所以我的int变量也总是32位。我将使用相同的布局(little-endian),这样我就不必每次将变量值加载到寄存器中或将寄存器存储回变量中时都进行转换。

使用godbolt,我们可以看到编译器对一些琐碎的代码做了什么:

int square(int num) {
    return num * num;
}
square(int):
  imul edi, edi
  mov eax, edi
  ret
    null
unsigned mult (unsigned x, unsigned y)
{
    return x*y;
}

mult(unsigned int, unsigned int):
  mov eax, edi
  imul eax, esi
  ret

具有非标准宽度的等效代码

struct pair {
    unsigned x : 31;
    unsigned y : 31;
};

unsigned mult (pair p)
{
    return p.x*p.y;
}

mult(pair):
  mov eax, edi
  shr rdi, 32
  and eax, 2147483647
  and edi, 2147483647
  imul eax, edi
  ret

所有额外的指令都涉及到将输入格式(两个31位无符号整数)转换为处理器可以本机处理的格式。如果我们想将结果存储回一个31位的值,那么将会有另外一个或两个指令来执行此操作。

这种额外的复杂性意味着只有在节省空间非常重要的时候才会考虑这个问题。在本例中,与使用本机unsigneduint32_t类型相比,我们只节省了两个位,后者生成的代码要简单得多。

这和变长编码有很大的不同--我使用过其中的一些,它们很糟糕。每次加载都变成一个循环,而不是单个指令。每个商店也是一个循环。每个结构都是可变长度的,所以你不能自然而然地使用数组。

在随后的评论中,您一直在使用“高效”这个词,据我所知,在存储大小方面。我们有时确实会选择最小化存储大小--当我们将大量的值保存到文件或通过网络发送时,这一点很重要。折衷的是,我们需要将这些值加载到寄存器中,以便对它们进行任何操作,而执行转换并不是免费的。

当我们讨论效率时,我们需要知道我们在优化什么,以及权衡是什么。使用非本机存储类型是以处理速度换取空间的一种方法,有时也是有意义的。使用可变长度存储(至少用于算术类型),以更高的处理速度(以及代码复杂度和开发人员时间)换取通常最小的空间进一步节省。

 类似资料:
  • 我想按英寸计算设备大小。我使用的是每次搜索都会出现的代码。但问题是,当我把设备放在4.5英寸时,我在android studio中的答案是4英寸。我尝试了5.2英寸的设备,得到了4.3英寸和10.1英寸-

  • 问题内容: 这是 不是 增加Java的堆的最大尺寸的虚拟机启动后。技术原因是什么?垃圾回收算法是否取决于要使用固定数量的内存?还是出于安全原因,通过消耗所有可用内存来防止Java应用程序从DOS的系统中移至其他应用程序? 问题答案: 最后我知道在Sun的JVM中,必须在连续的地址空间中分配整个堆。我想对于大堆值,很难在启动后将其添加到您的地址空间中,同时又要确保它保持连续。您可能需要在启动时获取它

  • 问题内容: 我注意到秋千上的容器之间有奇怪的行为。 为了举例说明该测试,我创建了一个JFrame和一个JPanel,并将面板设置为 contentPane。我将首选和最大的JPanel大小定义为400,300。所有 这些都可以在下面的示例中看到: The result is: 令我惊讶的是,终端的输出为: 面板尺寸:[400,300] 框架尺寸:[416,338] 我不明白为什么框架会增加这个额外

  • 我有一个用C实现的编程语言的小VM。它支持在32位和64位架构以及C和C下编译。 我正试图让它以尽可能多的警告来干净地编译。当我打开时,我会收到一连串新的警告。 对于何时使用而不是显式无符号类型和/或显式大小的类型,我想有一个很好的策略。到目前为止,我很难决定应该采取什么策略。 当然,混合它们——主要使用来处理局部变量和参数之类的事情,并为结构中的字段使用较窄的类型——会导致许多隐式转换问题。 我

  • 初学者问题,很抱歉,如果这不是一个合适的地方,请尝试学习在中逻辑是如何工作的,我无法理解这一点 我希望它会说“是的!”如果是A、A、D或D,而是z,但出于某种原因,它会说“是的!”无论第一个符号是什么,都会断开,并且只检查第二个符号是否为z。

  • 我目前正在学习做rosalind问题(基本上是一堆与生物信息学相关的代码)。 我目前正在用以下类型表示一条DNA链: 我最初的原因是封装字节片,这样我就知道它只包含代表核苷酸的字节:。我意识到这显然没有保护,因为我可以简单地做: 也不再保证我的dna链包含一个字节数组,其中只有来自这四个字节的元素。 因为我的结构只包含一个字节数组是更好/更理想的做法: 还是让类型包含dna链更好?对于何时使用这两