使用(或不使用)stdint的原因

Sas*_*ssa 46 c char stdint

我已经知道stdint用于当你需要特定的变量大小来实现平台之间的可移植性时,我现在还没有真正有这样的问题,但除了已经在上面显示的事实之外,使用它的缺点和优点是什么?

在stackoverflow和其他网站上寻找它,我找到了2个关于主题的链接:

  • 1 - 这个讨论了stdint的可移植性.

  • 2 - 这个更具体的关于uint8_t.

这两个链接非常好,特别是要了解更多关于这个标题的可移植性的主要原因,但对我来说,我最喜欢它,我认为uint8_t比unsigned char更清洁(例如存储RBG通道值) ,int32_t看起来比简单的int等更有意义.

所以,我的问题是,究竟是什么缺点,特别是除了可移植性之外使用stdint的优点,我应该只在代码的某些特定部分使用它,还是在任何地方?如果到处都是,我怎样才能使用atoi,strtok等功能呢?

谢谢!

Lun*_*din 70

优点

使用定义良好的类型使代码更容易和更安全地移植,因为当例如一台机器解释int为16位而另一台机器解释为32位时,您不会感到惊讶.使用stdint.h,您输入的内容就是您所获得的内容.

使用int等也使得难以检测危险类型的促销.

另一个优点是,通过使用int8_t而不是char,您知道您总是得到一个带符号的8位变量.char可以是有符号或无符号的,它是实现定义的行为,并且在编译器之间有所不同.因此,在char应该是可移植的代码中使用默认值是很危险的.

如果你想给编译器提供一个应该优化变量的提示,你可以使用uint_fastx_t它告诉编译器使用尽可能快的整数类型,至少和'x'一样大.大多数情况下这无关紧要,编译器足够智能,无论您输入什么内容,都可以对类型大小进行优化.在序列点之间,编译器可以隐式地将类型更改为指定的类型,只要它不影响结果.

缺点

没有.


参考:MISRA-C:2004规则6.3." 用于表示尺寸和符号的typedef应用于代替基本类型".

编辑:删除了错误的示例.

  • `uint32_t`不能存在于12位机器上. (14认同)
  • Wallyk所说的明显缺点是性能影响.强制在12位机器上计算uint32_t整数是很乏味的 (3认同)
  • @hroptatyr如果你再次阅读我的答案,你会发现我解决了这个问题.如果它需要是`uint32_t`,请将其声明为.如果它不需要那么高的分辨率,只需要16位,那么将它声明为`uint_fast16_t`,它将在32位编译为32位的CPU上编译为32位. (3认同)

R..*_*R.. 16

使用uint8_t而不是unsigned char(除了审美偏好)的唯一原因是,如果您想要记录您的程序需要char正好8位.uint8_t当且仅当CHAR_BIT==8符合C标准的要求时才存在.

其余的intX_t和uintX_t类型在以下情况下很有用:

  • 读/写磁盘/网络(但是你还必须使用字节序转换功能)
  • 当你想要一个精确截止值的无符号环绕行为时(但这可以通过&运算符更方便地完成).
  • 当您控制结构的确切布局时,因为您需要确保不存在填充(例如,用于memcmp或散列目的).

另一方面,uint_least8_t等等类型在您希望避免使用浪费的大型或慢速类型的任何地方都很有用,但需要确保您可以存储特定大小的值.例如,虽然long long至少是64位,但在某些机器上它可能是128位,并且当你需要的只是一种可以存储64位数字的类型时使用它会在这些机器上非常浪费.int_least64_t解决了这个问题.

我会[u]int_fastX_t完全避免使用这些类型,因为它们有时会在给定的机器上发生变化(打破ABI),因为定义通常是错误的.例如,在x86_64上,64位整数类型被认为是16位,32位和64位值的"快速"类型,但是无论您使用32位,加法,减法和乘法都是完全相同的速度对于比特或64比特的值,除了大于必要类型之外,除法几乎肯定更慢,即使它们是相同的速度,你使用两倍的内存也没有任何好处.

最后,请注意,int32_t当一个计数器不是本机整数大小时,一些答案对于使用计数器的低效率的论据在技​​术上大多是正确的,但它与正确的代码无关.除非你计算一些最小数量在你控制之下的东西,或者一些外部(不在程序内存中)计数可能是天文数字的东西,否则计数的正确类型几乎总是如此size_t.这就是所有标准C函数size_t用于计数的原因.除非你有充分的理由,否则不要考虑使用其他任何东西.

  • int_fastx_t的问题听起来像编译器错误,而不是程序员应该关注的事情.我同意在大多数情况下,计数器变量(对于循环int交互器等)应该是size_t. (2认同)

wal*_*lyk 7

缺点

主要原因C语言不指定的尺寸int或long等是用于计算效率.每个体系结构都具有自然,最有效的大小,并且设计人员特别授权并希望编译器实现者使用自然原生数据大小数据来提高速度和代码大小效率.

在过去的几年中,与其他机器的通信并不是主要问题 - 大多数程序都是机器的本地程序 - 所以每种数据类型的大小的可预测性几乎没有引起关注.

坚持特定的架构使用特定的大小int来计算是一个非常糟糕的主意,即使它似乎使其他事情更容易.

在某种程度上,由于XML及其兄弟,数据类型的大小再次不再是一个问题.从机器到机器的特定于机器的二元结构也是例外,而不是规则.

  • -1,你不知道标准.stdint.h不仅包含`uintx_t`,还包含`uintx_least_t`和`uintx_fast_t`.此外,在移植代码时,您不希望突然发生类型大小更改的任何意外.如果可移植性很重要,代码应该使用适用于任何机器的类型.我使用基本的stdint类型,而不是快速的类型,并且经常在小型8位MCU和繁琐的64位PC之间进行端口切换,没有任何问题.当我这样做时,不必重写代码,对我来说实际上似乎是个好主意. (14认同)
  • @Lundin:类似`int16_fast_t`这样的类型会更有用,如果标准允许编译器在不需要总是给它的情况下提高效率的情况下提供额外的精度.如果变量的范围可能取决于它是否存储在寄存器中,即使存在一个规则要求任何特定变量的范围是到处都是制服 在这样的规则下,`int16_fast_t`可以在许多机器上像`int16_t`一样紧凑,而...... (3认同)
  • ...如果它被提升为"int",仍然可以获得所有可以实现的速度优势. (3认同)

hro*_*tyr 6

我只使用stdint类型有一个原因,当我在内存中保存的数据应以二进制形式存在于磁盘/网络/描述符上时.你只需要对抗小端/大端问题,但这相对容易克服.

不使用stdint 的明显原因是当代码与大小无关时,在数学术语中,所有对于有理整数都有效.如果你为每次扩展提供了一个uint*_t版本,它会产生丑陋的代码重复.qsort()*

在这种情况下,我使用自己的类型,从size_t我懒惰时得到,或者当我不是时,从平台上获得最大支持的无符号整数.

编辑,因为我遇到了这个问题前面:
我认为这是值得关注的至少,在uint8_t,uint32_t并uint64_t在Solaris 2.5.1上被打破.因此,为了获得最大的便携性,我仍然建议避免stdint.h(至少在接下来的几年内).