【问题标题】:Should I use the stdint.h integer types on 32/64 bit machines?我应该在 32/64 位机器上使用 stdint.h 整数类型吗?
【发布时间】:2017-04-11 04:19:07
【问题描述】:

让我对常规 c 整数声明感到困扰的一件事是它们的名称很奇怪,“long long”是最糟糕的。我只为 32 位和 64 位机器构建,所以我不一定需要该库提供的可移植性,但是我喜欢每种类型的名称都是长度相似的单个单词,大小没有歧义。

// multiple word types are hard to read
// long integers can be 32 or 64 bits depending on the machine

unsigned long int foo = 64;
long int bar = -64;

// easy to read
// no ambiguity

uint64_t foo = 64;
int64_t bar = -64;

在 32 位和 64 位机器上:

1) 使用较小的整数(例如 int16_t)会比使用较大的整数(例如 int32_t)慢吗?

2) 如果我需要一个 for 循环来运行 10 次,是否可以使用可以处理它的最小整数而不是典型的 32 位整数?

for (int8_t i = 0; i < 10; i++) {

}

3) 每当我使用我知道永远不会为负的整数时,即使我不需要提供的额外范围,是否可以更喜欢使用无符号版本?

// instead of the one above
for (uint8_t i = 0; i < 10; i++) {

}

4) 对 stdint.h 中包含的类型使用 typedef 是否安全

typedef int32_t signed_32_int;
typedef uint32_t unsigned_32_int;

编辑:两个答案都一样好,我不能真正倾向于一个,所以我只选择了代表较低的回答者

【问题讨论】:

标签: c integer typedef stdint


【解决方案1】:

1) 使用较小的整数(例如 int16_t)会比使用较大的整数(例如 int32_t)慢吗?

是的,它可以更慢。请改用int_fast16_t。根据需要分析代码。性能非常依赖于实现。 int16_t 的一个主要好处是它在结构和数组中使用的体积小、定义明确(也必须是 2 的补码),而不是速度。

typedef 名称int_fastN_t 指定最快的有符号整数类型,其宽度至少为N。 C11 §7.20.1.3 2


2) 如果我需要一个 for 循环只运行 10 次,是否可以使用可以处理它的最小整数而不是典型的 32 位整数?

是的,但是在代码和速度方面的节省是值得怀疑的。建议使用int。使用本机 int 大小,发出的代码在速度/大小方面往往是最佳的。


3) 每当我使用一个我知道永远不会为负的整数时,即使我不需要提供的额外范围,是否可以更喜欢使用无符号版本?

当数学严格无符号时(例如使用size_t 的数组索引),首选使用一些无符号类型,但代码需要注意像这样粗心的应用程序

for (unsigned i = 10 ; i >= 0; i--) // infinite loop

4) 对 stdint.h 中包含的类型使用 typedef 是否安全

几乎总是。 int16_t 之类的类型是可选的。最大可移植性使用所需的类型 uint_least16_tuint_fast16_t 让代码在使用 9、18 等位宽的稀有平台上运行。

【讨论】:

  • 关于可选:“这些类型是可选的。但是,如果实现提供了宽度为 8、16、32 或 64 位的整数类型,则没有填充位,并且(对于有符号类型)具有二进制补码表示,它应定义相应的 typedef 名称。” (§ 7.20.1.1/3 N1570“准 C11”)。我认为 that 几乎可以匹配任何实现...(现在)
【解决方案2】:

使用较小的整数(例如 int16_t)会比使用较大的整数(例如 int32_t)慢吗?

是的。有些 CPU 没有专用的 16 位算术指令; 16 位整数的算术运算必须使用如下指令序列来模拟:

r1 = r2 + r3
r1 = r1 & 0xffff

同样的原则也适用于 8 位类型。

使用&lt;stdint.h&gt; 中的“快速”整数类型来避免这种情况——例如,int_fast16_t 将为您提供一个至少 16 位宽的整数,但如果16 位类型不是最优的。

如果我需要一个 for 循环只运行 10 次,是否可以使用可以处理它的最小整数而不是典型的 32 位整数?

不要打扰;只需使用int。使用较窄的类型实际上并不会节省任何空间,如果您决定将迭代次数增加到 127 次以上并忘记循环变量使用的是窄类型,则可能会导致问题发生。

每当我使用我知道永远不会为负的整数时,即使我不需要提供的额外范围,是否可以更喜欢使用无符号版本?

最好避免。某些 C 习语不能在无符号整数上正常工作;例如,您不能编写如下形式的循环:

for (i = 100; i >= 0; i--) { … }

如果i 是无符号类型,因为i &gt;= 0 将永远为真!

对 stdint.h 中包含的类型使用 typedef 是否安全

从技术角度来看是安全的,但它会惹恼其他必须使用您的代码的开发人员。

习惯 &lt;stdint.h&gt; 的名字。它们是标准化的并且相当容易键入。

【讨论】:

  • "使用更窄的类型 [...]" - 并且使用比处理器的寄存器大小更宽的类型甚至会减慢程序的速度...“只使用 int”通常是正确的,一个例外:如果您对可能不适合 int 的大值进行操作,那么在这种情况下,人们可能更喜欢 [...]fast[...] 类型。 “最好避免” - 再次例外:for(i = 0; i
【解决方案3】:
  1. 绝对有可能,是的。在我的笔记本电脑(Intel Haswell)上,在一个微基准测试中,两个寄存器在 0 到 65535 之间上下计数 20 亿次,这需要

    1.313660150s - ax dx (16-bit)
    1.312484805s - eax edx (32-bit)
    1.312270238s - rax rdx (64-bit)
    

    时间上的微小但可重复的差异。 (我在汇编中编写了基准测试,因为 C 编译器可能会将其优化为不同的寄存器大小。)

  2. 它会起作用,但如果你改变界限,你必须保持它是最新的,C 编译器可能会将它优化为相同的汇编代码。

  3. 只要 C 是正确的,那完全没问题。请记住,无符号溢出是已定义的,而有符号溢出是未定义的,编译器确实利用它进行优化。例如,

    void foo(int start, int count) {
        for (int i = start; i < start + count; i++) {
            // With unsigned arithmetic, this will execute 0 times if
            // "start + count" overflows to a number smaller than "start".
            // With signed arithmetic, that may happen, or the compiler
            // may assume this loop always runs "count" times.
            // For defined behavior, avoid signed overflow.
        }
    
  4. 是的。此外,POSIX 提供了inttypes.h,它扩展了stdint.h 一些有用的函数和宏。

【讨论】:

    猜你喜欢
    • 2012-05-26
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-23
    • 1970-01-01
    相关资源
    最近更新 更多