【问题标题】:Why do fixed width types delegate back to primitives?为什么固定宽度类型委托回原语?
【发布时间】:2017-02-05 21:51:27
【问题描述】:

Visual Studio 14 中,stdint.h 标头具有固定宽度整数类型的定义,但如果您真正查看那里的定义,它们只是委托给原语。定义如下:

typedef signed char        int8_t;
typedef short              int16_t;
typedef int                int32_t;
typedef long long          int64_t;
typedef unsigned char      uint8_t;
typedef unsigned short     uint16_t;
typedef unsigned int       uint32_t;
typedef unsigned long long uint64_t;

那么,如果 stdint.h 所做的只是回退到原语,那么还有什么理由使用它?我也知道 Visual Studio 不只是在编译时替换这些定义,因为如果您尝试将 int8_t 打印到控制台,您将得到一个 Unicode 字符而不是数字,因为它实际上只是一个 signed char

编辑

因为人们指出,他们在逻辑上没有其他任何东西可以定义,我认为我的问题需要重申。

为什么在 C++ 规范中声明它将具有 8、16、32 和 64 位固定长度的整数的标头将这些整数定义为根据定义可以是编译器想要的任何大小的类型(到用别人在另一个问题The compiler can decide that an int will a 71 bit number stored in a 128 bit memory space where the additional 57 bits are used to store the programmers girlfriends birthday.) 中所说的方式?

【问题讨论】:

  • typedef 的代表还会回复什么?并在 C++ 中使用<cstdint>,因为<stdint.h> 已弃用
  • @DeiDei stdint.h 应该包含固定宽度的整数,因为编译器可以将原语定义为几乎任何东西。
  • 是的,编译器将原语定义为适合平台大小,库负责使stdint.h 中的typedef 正确。不要对 Visual C++ 做出太多判断,因为它仅适用于 Windows,并且其中的整数类型变化不大。
  • @DeiDei OS X 也有基本相同的定义。
  • @DeiDei 我选择使用stdint.h 而不是cstdint 因为cstdint 只是回退到stdint.h

标签: c++ visual-c++ stdint


【解决方案1】:

不同平台对原语的定义不同。在一个平台上int 可能是 16 位,而在另一个平台上它是 32 位。如果您严格依赖具有特定宽度的变量,则应使用stdint.h 中的类型,对于当前平台上它们各自的原语,它们将始终正确地使用typedef

【讨论】:

  • 我认为是编译器决定了你的数字的大小。我知道 stdint.h 的用途,但它只是 typedef 回到了可以由编译器设置的原语。
  • 在非常旧的系统上,许多编译器将 int 设置为 8 位,因为 int 被视为您用于循环和其他通用内容的类型,因此将没有它有一个系统不能很好地处理的宽度。所以是的,这是编译器的决定,一些编译器决定定义不同的原语以具有不同的大小,以适应他们的目标平台。虽然,公平地说,现在你几乎可以依赖它在任何地方都是一样的。
  • @vandench:是的,这是真的。但是标准库实现通常与编译器一起分发,编写一个的人熟悉另一个的细节(如果他们不是同一个人)。与 gcc 一起分发的 "stdint.h" 文件可能看起来与与 Visual Studio 一起分发的文件不同。
  • @Lignum “在非常古老的系统上,许多编译器将 int 设置为 8 位”为此提供一些证据。我从未遇到过字长(即 sizeof(int) 小于 16 位)的 C 编译器。即使在为 Z80 等 8 位处理器编写汇编代码时,我们通常也将通用整数视为 16 位字. 像 Z80 这样的 8 位是数据总线的大小,而不是我们认为的整数的大小。
  • @NeilButterworth 好吧,那可能不准确,我不是逆向计算方面的专家,但你明白了。
【解决方案2】:

如果 stdint.h 所做的只是回退到原语,那么还有什么理由使用它?

它还能做什么?

标头中定义的所有类型都可以追溯到内置类型。

此标头只是为您提供方便、标准定义、保证一致的别名。

【讨论】:

  • 我想值得一提的是,typedef 的问题是根据标准可选,并且如果平台支持它们就可用。 int_leastN_t 以获得更多便携性。
【解决方案3】:

我从原始问题和重述问题中了解到,对于保证宽度整数(我说保证是因为并非stdint.h 中的所有类型都具有固定宽度)以及它们解决的实际问题存在误解。

C/C++ 定义诸如intlong intlong long int 等原语。为简单起见,让我们关注最常见的,即int。 C 标准定义的是,int 至少应为 16 位宽。但是,所有广泛使用的 x86 平台上的编译器实际上会在您定义 int 时为您提供一个 32 位宽的整数。发生这种情况是因为 x86 处理器可以直接从内存中获取 32 位宽的字段(32 位 x86 CPU 的字长),按原样提供给 ALU 以进行 32 位运算并将其存储回内存,而无需执行任何操作班次,填充等,这非常快。但并非每个编译器/架构组合都是如此。如果你在一个嵌入式设备上工作,例如一个非常小的 MIPS 处理器,当你定义一个 int 时,你可能会从编译器中得到一个 16 位宽的整数。 因此,原语的宽度由编译器指定,仅取决于目标平台的硬件功能,相对于标准定义的最小宽度。 是的,在一个奇怪的架构上,例如一个 25 位 ALU,您可能会得到一个 25 位 int

为了让一段 C/C++ 代码在许多不同的编译器/硬件组合之间可移植,stdint.h 提供了 typedef 来保证一定的宽度(或最小宽度)。因此,例如,当您想使用 16 位有符号整数(例如,用于节省内存或 mod 计数器)时,您不必担心是否应该使用 intshort,只需使用int16_t编译器的开发人员将为您提供一个正确构造的stdint.h,它将请求的固定大小整数类型定义为实现它的实际原语。这意味着,在 x86 上,int16_t 可能是定义为short,而在小型嵌入式设备上,您可能会得到int,所有这些映射都由编译器的开发人员维护。

【讨论】:

    【解决方案4】:

    在回答重述的问题时,不是编译器选择将生日存储在高 57 位中。那是一个开发商。编译器不能对整数类型使用它想要的任何位深度。它将使用编译器的开发人员告诉它使用的任何位深度,并且开发人员将根据the requirements of the C++ standard 选择这些位深度。一旦编译器被配置和编译,位深度将不会改变1。在您更改编译器或编译器版本之前,将保证 71 位。

    编写好的代码已经够难了,编译器不会向你抛出变量。考虑可变位深度会发生什么。一个在周二构建中很好的输入溢出并导致一架喷气式客机坠毁,因为周三编译器执行了一些计算并决定它永远不会看到超过 17 位的任何内容。

    1 我想您可以构建一个编译器,在运行时从配置文件中加载各种整数大小,但我怀疑这会使编写优化器变得异常复杂。

    【讨论】:

      猜你喜欢
      • 2011-12-15
      • 2012-09-13
      • 1970-01-01
      • 2021-05-10
      • 1970-01-01
      • 1970-01-01
      • 2015-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多