谁决定任何数据类型或结构的大小(取决于32位还是64位)?

Vis*_*Lia 44 c c++ linux compiler-construction operating-system

谁决定任何数据类型或结构的大小(取决于32位还是64位)?编译器还是处理器?例如,sizeof(int)32位系统是4个字节,而64位系统是8个字节.

我还读到sizeof(int)使用32位和64位编译器编译时的4个字节.

假设我的CPU能为64位应用程序,谁在决定数据的大小起到主要作用同时运行32位和编译器或处理器

Pro*_*ica 43

它最终是编译器.无论CPU处理效率最高,编译器实现者都可以决定模拟他们认为合适的整数大小.也就是说,编写C(和C++)标准,编译器实现者可以自由选择最快,最有效的方法.对于许多编译器,实现者选择将int保持为32位,尽管CPU本身非常有效地处理64位整数.

我认为这部分是为了增加对32位机器最常见并且期望int为32位而不再是int的程序的可移植性.(也可能是,正如用户user3386109指出的那样,32位数据是首选,因为它占用的空间更少,因此可以更快地访问.)

因此,如果您想确保获得64位整数,则使用int64_t而不是int声明您的变量.如果你知道你的值适合32位或者你不关心大小,你int可以让编译器选择最有效的表示.

至于其他数据类型,例如struct,它们由基类型组成int.

  • `int64_t`不需要存在.需要`long long`,并且它总是至少64位宽; 当硬件不直接支持它时,编译器将生成适当的代码. (6认同)
  • @CortAmmon - 语言定义要求`long long`至少为64位宽.它有点难找,因为它在库部分.它来自C标准,它要求`LLONG_MIN`必须不大于 - (2 ^ 63-1)并且LLONG_MAX必须不小于2 ^ 63-1. (5认同)
  • 或者32位用于节省内存并提高缓存性能.填充缓存行不需要很多64位整数. (3认同)
  • @Justin,在关于编译器如何选择任何大小以提供最快或最有效结果的许多方法的部分中提到的. (2认同)
  • 使用16位`int`"如果你知道你的值将适合32位或你不关心大小,你使用`int`让编译器选择最有效的表示." 是不好的建议.2016年每年有100万台嵌入式处理器使用16位`int`.虽然Linux的程序不需要担心,因为操作系统推动32_bit`int`或更宽. (2认同)
  • @CortAmmon - 为了完整性:`char`必须至少为8位宽; "短"至少16; `int`至少16; `long`至少32; 和`long long`至少64.相同的`signed char`和所有`unsigned`变种. (2认同)

Art*_*Art 26

它不是CPU,也不是编译器,也不是操作系统.这三个是同时进行的.

编译器不能只是搞砸了.它必须遵守操作系统提供的正确的ABI [1].如果操作系统提供的结构和系统调用具有某些大小和对齐要求的类型,那么除非编译器开发人员想要为操作系统提供的所有内容重新实现包装函数,否则编译器实际上无法自行构建自己的实际情况.然后操作系统的ABI不能完全组成,它必须做可以在CPU上合理完成的事情.通常,一个操作系统的ABI与同一CPU上其他操作系统的其他ABI非常相似,因为它更容易重用他们所做的工作(在编译器等).

如果计算机同时支持32位和64位代码,则操作系统仍需要完成工作以支持在两种模式下运行程序(因为系统必须提供两种不同的ABI).有些操作系统没有这样做,而有些操作系统则没有选择.

[1] ABI代表应用程序二进制接口.它是程序如何与操作系统交互的一组规则.它定义了程序如何存储在磁盘上以便操作系统可以运行,如何进行系统调用,如何与库链接等等.但是为了能够链接到库,例如,您的程序和库必须同意关于如何在程序和库之间进行函数调用(反之亦然),并且为了能够进行函数调用,程序和库必须具有相同的堆栈布局,寄存器用法,函数调用约定等概念.对于函数调用,您需要就参数的含义达成一致,包括类型的大小,对齐和签名.

  • 不需要编译器支持程序可以与外部世界中的任何内容交互的任何方式,而无需通过与编译器捆绑在一起的库函数.没有什么能禁止使用36位的补码整数类型来实现针对x64的实现(执行任何移位和模拟操作所需的屏蔽操作).如果某人有一些他们想要运行的Univac代码但是他们没有一个可用的36位系统,那么这样的实现可能真的很有用. (4认同)
  • Upvoted是因为它给出了"非常基于实际现实"的角度. (2认同)
  • @MartinBonner好吧,使用那个参数不是编译器,而是你.因为您可以选择编译器.除了,也许没有自由意志,那就是选择的宇宙.大爆炸设置了参数,这些参数导致您选择一个编译器,该编译器由参数使他们为类型选择特定大小的人编写.另一方面,在我居住的现实中,我们有编译器以有用的方式与他们的环境进行交互,人们不会浪费时间来构建无用的编译器,但有些人仍然浪费时间来争论它可以完成. (2认同)
  • @WillCrawford有很多用于Windows的x64编译器使用了一些与Windows x64调用约定完全不同的组合ABI.因为他们决定引入整个Linux ABI包,并且完全正是这样做的. (2认同)

use*_*003 8

严格地说,100%完全是编译器决定sizeof(int)的值.它不是系统和编译器的组合.它只是编译器(和C/C++语言规范).

如果您开发iPad或iPhone应用程序,则可以在Mac上运行编译器.Mac和iPhone/iPac使用不同的处理器.没有任何关于你的Mac告诉编译器应该在iPad上使用int的大小.

  • 这根本不是真的.至少你承认"语言规范",但是每个系统都有一个标准(ABI),其大小是默认的"int",参数如何传递给函数等等......例如对于iOS应用程序,[这个Apple开发人员指南](https://developer.apple.com/library/content/documentation/General/Conceptual/CocoaTouch64BitGuide/Major64-BitChanges/Major64-BitChanges.html)说出来: (2认同)

plu*_*ash 5

处理器设计者确定哪些寄存器和指令可用,有效访问的对齐规则是什么,内存地址有多大等等.

C标准设置了内置类型的最低要求."char"必须至少为8位,"short"和"int"必须至少为16位,"long"必须至少为32位,"long long"必须至少为64位.它还说"char"必须与程序可以解决的最小内存单元相等,并且必须保持标准类型的大小顺序.

其他标准也可能产生影响.例如,"单一Unix规范"的版本2表示int必须至少为32位.

最后,现有代码会产生影响.移植已经很难了,没有人想让它变得更难.


将操作系统和编译器移植到新CPU时,有人必须定义所谓的"C ABI".这定义了二进制代码如何相互通信,包括.

  • 内置类型的大小和对齐要求.
  • 结构的包装规则(以及它们的尺寸).
  • 如何传递和返回参数
  • 如何管理堆栈

一般而言,一旦ABI被定义为CPU系列和OS的组合,它的变化不大(有时像"长双"变化这样的更模糊类型的大小).改变它会带来一堆破损,收益相对较小.

类似地,将操作系统移植到具有与现有操作系统类似特征的平台的那些通常会选择与移植到操作系统的先前平台相同的大小.


实际上,OS /编译器供应商通常会选择基本整数类型的几种大小组合之一.

  • "LP32":char是8位.short和int是16位,long和指针是32位.常用于8位和16位平台.
  • "ILP32":char为8位,short为16位.int,long和指针都是32位.如果长时间存在则为64位.常用于32位平台.
  • "LLP64":char是8位.short是16位.int和long是32位.long long和指针是64位.用于64位窗口.
  • "LP64":char是8位.short是16位.int是32位.long,long long和指针是64位.用于大多数64位unix类系统.
  • "ILP64":char为8位,short为16位,int,long和指针,long long均为64位.显然在一些早期的64位操作系统上使用,但现在很少见.

64位处理器通常可以运行32位和64位二进制文​​件.通常,这是通过在操作系统中使用兼容层来处理的.因此,您的32位二进制文​​件使用与在32位系统上运行时相同的数据类型,然后兼容层会转换系统调用,以便64位操作系统可以处理它们.