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

C++ 谁决定任何数据类型或结构的大小(取决于32位或64位)?,c++,c,linux,compiler-construction,operating-system,C++,C,Linux,Compiler Construction,Operating System,谁决定任何数据类型或结构的大小(取决于32位或64位)?编译器还是处理器?例如,sizeof(int)对于32位系统是4字节,而对于64位系统是8字节 我还了解到,当同时使用32位和64位编译器编译时,sizeof(int)是4个字节 假设我的CPU既可以运行32位应用程序,也可以运行64位应用程序,谁将在决定编译器或处理器的数据大小方面发挥主要作用。编译器实现者可以决定模拟他们认为合适的任何整数大小,而不管CPU最有效地处理什么。也就是说,C(和C++)标准是这样编写的,编译器实现者可以自由选

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

我还了解到,当同时使用32位和64位编译器编译时,
sizeof(int)
是4个字节


假设我的CPU既可以运行32位应用程序,也可以运行64位应用程序,谁将在决定编译器或处理器的数据大小方面发挥主要作用。编译器实现者可以决定模拟他们认为合适的任何整数大小,而不管CPU最有效地处理什么。也就是说,C(和C++)标准是这样编写的,编译器实现者可以自由选择最快和最有效的方法。对于许多编译器,实现者选择将int保持为32位,尽管CPU本机处理64位int非常有效

我认为这样做的部分原因是为了提高程序的可移植性,当时32位机器是最常见的,他们希望int为32位,而不再是。(作为用户,32位数据可能更受欢迎,因为它占用的空间更少,因此访问速度更快。)

因此,如果要确保获得64位整数,可以使用
int64\u t
而不是
int
来声明变量。如果您知道您的值将在32位之内,或者您不关心大小,那么可以使用
int
让编译器选择最有效的表示形式


至于其他数据类型,如
struct
,它们是由基本类型(如
int

)组成当你谈论编译器时,你必须对
build | host | target
有一个清晰的印象,即你正在构建的机器(build),你正在构建的机器(host),GCC将为(目标)生成代码的机器,因为“交叉编译”与“本机编译”非常不同

关于“谁决定数据类型和结构的大小”的问题,这取决于您告诉编译器为其构建二进制文件的目标系统。如果目标是64位,编译器将把sizeof(long)翻译成8,如果目标是32位机器,编译器将把sizeof(long)翻译成4。所有这些都是由您用来构建程序的头文件预定义的。如果您阅读“$MAKETOP/usr/include/stdint.h”,则会有typedef来定义数据类型的大小

为避免大小差异造成的错误,建议使用int16\u t、uint32\u t、int64\u t等类型。这些类型在
中定义


上面只是那些“普通的旧数据”,比如int。如果你谈论一个结构,还有另一个故事,因为结构的大小取决于结构中每个字段的边界对齐,这将影响结构的大小。

不是CPU,也不是编译器,也不是操作系统。这三个都是同时发生的

编译器不能只是编造东西。它必须遵循操作系统提供的正确ABI[1]。如果操作系统提供的结构和系统调用具有特定大小和对齐要求的类型,编译器就不能真正自由地构建自己的现实,除非编译器开发人员希望为操作系统提供的所有内容重新实现包装器函数。那么,操作系统的ABI就不能完全由CPU来完成,它必须做一些可以在CPU上合理完成的事情。通常,一个操作系统的ABI与同一CPU上的其他操作系统的ABI非常相似,因为能够重用它们所做的工作(在编译器上等等)更容易

对于同时支持32位和64位代码的计算机,仍然需要操作系统完成工作以支持在两种模式下运行程序(因为系统必须提供两种不同的ABI)。有些操作系统不能做到这一点,在那些你别无选择的操作系统上


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

编译器决定基本类型的大小,结构的布局是什么。如果库声明了任何类型,它将决定如何定义这些类型以及它们的大小


然而,通常情况下,与现有标准的兼容性以及链接到其他编译器生成的现有库的需要迫使给定的实现做出某些选择。例如,语言标准规定,
wchar\u t
必须大于16位,在Linux上,它是32位宽,但在Windows上总是16位,因此Windows编译器都选择与Windows API兼容,而不是与语言标准兼容。Linux和Windows的许多传统代码都假定
long
正好是32位宽,而其他代码则假定它的宽度足以容纳以秒为单位的时间戳、IPv4地址、文件偏移量或指针位,并且(在一个编译器将
int
定义为64位宽和
long
定义为32位宽后)语言站