我应该在32/64位机器上使用stdint.h整数类型吗?

时间:2017-04-11 04:19:08

标签: c integer typedef stdint

有关常规c整数声明的一个问题是,他们的名字很奇怪,"很长很长"是最糟糕的。我只为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;

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

3 个答案:

答案 0 :(得分:3)

  

使用较小的整数(如int16_t)可以比较高的整数(如int32_t)慢吗?

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

            SELECT c.cust_id, `c`.`cust_contact_name`, `c`.`cust_active_flag`, 
            (select COUNT(`pm`.`cust_id`)  from property_master as pm 
            Where pm.cust_id = c.cust_id) as prop_count,
            (select a.addr_phoneno1 from address as a
            WHERE a.cust_id = c.cust_id AND a.addr_type_flag IN ('C', 'CP')) as cust_phone,
            (select count(ci.cust_id) from customer_inquiry as ci
            WHERE ci.cust_id = c.cust_id) as inquiry_count,
            (select max(inq_date) from customer_inquiry as ci
            WHERE ci.cust_id = c.cust_id) as last_inq_date
            FROM customer as c
            GROUP BY c.cust_ID

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

使用r1 = r2 + r3 r1 = r1 & 0xffff 中的“快速”整数类型来避免这种情况 - 例如,<stdint.h>将为您提供至少 16位宽的整数,但是如果16位类型不是最优的,则可能更宽。

  

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

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

  

每当我使用一个我知道永远不会是负数的整数时,即使我不需要提供额外的范围,也可以选择使用无符号版本吗?

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

int

如果for (i = 100; i >= 0; i--) { … } 是无符号类型,因为i将永远为真!

  

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

从技术角度看是安全的,但它会让其他需要使用您的代码的开发人员感到烦恼。

习惯i >= 0名称。它们是标准化的,并且相当容易打字。

答案 1 :(得分:3)

  

1)使用较小的整数(如int16_t)可以比较高的整数(如int32_t)慢吗?

是的,它可能会变慢。请改用int_fast16_t。根据需要配置代码。性能非常依赖于实现。 int16_t的一个主要好处是它在结构和数组中使用的小的,定义良好的大小(也必须是2的补码),而不是速度。

  

typedef名称int_fastN_t指定宽度至少为 N 的最快签名整数类型。 C11§7.20.1.32

  

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等的稀有平台上运行代码。

答案 2 :(得分:1)

  1. 绝对可能,是的。在我的笔记本电脑(Intel Haswell)上,在一个微基准测试中,在两个寄存器上向上和向下计数0到65535,这需要

    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一些有用的函数和宏。