【问题标题】:What defines the size of a type?什么定义了类型的大小?
【发布时间】:2019-10-03 00:30:24
【问题描述】:

ISO C 标准规定:

sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)

我在 BIT Linux mint (19.1) 上使用 GCC-8,long int 的大小为 8

我正在使用一个使用 GCC 7 且编译器是 64 位的应用程序。 long int 的大小为4。 编译器或操作系统是否定义了long int 的大小?

【问题讨论】:

  • 这可能会有所帮助,但它本身并不是一个答案:en.wikipedia.org/wiki/64-bit_computing
  • 据我所知,所有版本的 GCC 在编译 Linux x86_64 二进制文件时都使用 8 字节 long ints。另一方面,在编译 Linux x86 二进制文件时,它们都使用 4 字节 long ints。这与编译器的形式或主机无关,而与目标有关。
  • 我猜测 Windows 可能与 GCC 7 一起使用。Windows 具有 LLP64 数据模型,它将 long 定义为 32 位(4 字节)。
  • C 标准还需要sizeof(char) == 1sizeof(short)*CHAR_BIT &gt;= 16sizeof(int)*CHAR_BIT &gt;= 16sizeof(long)*CHAR_BIT &gt;= 32

标签: c gcc sizeof


【解决方案1】:

TL/DR - 确切的大小取决于编译器。


标准要求类型能够表示值的最小范围 - 例如,unsigned char 必须能够表示至少范围@ 987654322@,int 必须能够表示至少范围[-32767...32767]等。

该最小范围定义了最小位数 - 您需要至少 16 位来表示[-32767..32767] 的范围(某些系统可能使用作为字的一部分的填充位或奇偶校验位,但不用于表示值)。

其他架构考虑因素也起作用 - int通常设置为与本机字大小相同的大小。所以在 16 位系统上,int(通常)是 16 位,而在 32 位系统上是 32 位。所以,最终,它归结为编译器。

但是,可以让 32 位系统上的一个编译器使用 16 位 int,而另一个使用 32 位 int。这导致我在 90 年代中期浪费了一个下午,在那里我编写了一些代码,假设 32 位 int 在一个编译器下运行良好,但在另一个编译器下 打破了世界相同的硬件。

所以,吸取教训 - 永远不要假设一个类型可以表示标准保证的最小值之外的值。要么检查limits.hfloat.h 的内容以查看类型是否足够大,或者使用stdint.h 中的大小类型之一(int32_tuint8_t 等)。

【讨论】:

  • 注:除了各种类型范围要求外,标准还要求sizeof(char)==1
【解决方案2】:

这由实施自行决定。

实现(编译器和标准库)定义了longint 和所有其他类型的大小。

只要它们符合标准给出的约束,实现就可以决定类型的大小(可能除了指针)。

【讨论】:

    【解决方案3】:

    操作系统/架构的Application Binary Interface 指定基本类型的大小:

    ABI 涵盖详细信息,例如(粗体字):

    • 处理器指令集(包含寄存器文件结构、堆栈组织、内存访问类型等详细信息...)
    • 处理器可以直接访问的基本数据类型的大小、布局和对齐方式
    • 调用约定,控制函数参数的传递和返回值的检索方式;例如,是否所有 参数在堆栈上传递或一些在寄存器中传递, 哪些寄存器用于哪些函数参数,以及是否 堆栈上传递的第一个函数参数首先被压入或 最后入栈
    • 如果 ABI 指定直接系统调用而不是过程,应用程序应如何对操作系统进行系统调用 调用系统调用存根,系统调用号
    • 以及在完整操作系统ABI的情况下,目标文件、程序库等的二进制格式。

    【讨论】:

    • 编译器决定从其类型名称到 ABI 中的类型的映射。
    • @EricPostpischil 随意编辑。我怀疑你比我知道的更多。 ;-)
    • @EricPostpischil 我刚刚更改了对社区 wiki 的回答。一切都由你来改进。
    • tadman’s answer 是正确的。
    • ABI(顺便说一下,是自愿的)只能指定如何传递 8、16、32 或其他位数的整数,如何传递各种大小的浮点对象,如何传递结构,等等。它无法控制它们在编程语言中的名称。如果long 是编程语言中的 32 位整数,则它将在 ABI 中作为 32 位整数传递。如果long 在编程语言中是一个 64 位整数,那么它将在 ABI 中作为 64 位整数传递。 ABI 永远不会看到该名称。编译器决定名称的含义。
    【解决方案4】:

    编译器做主。操作系统只是运行生成的二进制文件。

    话虽如此,编译器通常会生成操作系统可以使用的可执行文件,所以这里有一些相互作用。因为像 int 的大小这样的东西并不重要只要它们是一致的,你会看到变化。

    换句话说,如果内核期望 long int 是 8 个字节,因为它是如何编译的,那么您将希望以这种方式编译以匹配,否则您的编译代码将不匹配并且没有任何共享库会工作的。

    【讨论】:

    • 值得注意的是,更现代的C代码经常使用不同的常量来避免歧义,比如those introduced in C99就像int64_t
    • @tadman ABI 没有限制编译器。遵守 ABI 使程序可以在特定系统上运行
    • @tadman 迂腐地,编译器生成与目标 ABI 兼容的二进制文件。但是由于 ABI 和编译器往往同时来自同一个人(一个没有另一个不是很有用,除非你喜欢汇编程序),它事实上更像是先有鸡还是先有蛋问题是说哪个先出现,哪个“规则”。
    • @AndrewHenle 说得比我好得多。谢谢。
    • @Michi: Re“我想更多地了解为什么同一个编译器在同一个编译器上使用不同的大小。如果操作系统是 64BIT,我无法理解其中的区别。”:操作系统只能控制软件与它的接口方式。如果有一个操作系统例程需要传递一个 32 位整数,那么您必须向它传递一个 32 位整数。但是,在程序内部,程序(和编译器)可以做任何他们想做的事情。如果编译器想要调用 32 位整数 int 并调用 48 位整数 gromitz,那么它可以。
    猜你喜欢
    • 2014-04-26
    • 2014-11-06
    • 1970-01-01
    • 1970-01-01
    • 2020-03-06
    • 1970-01-01
    • 1970-01-01
    • 2011-10-26
    • 2017-06-06
    相关资源
    最近更新 更多