【问题标题】:Should I use cstdint?我应该使用 cstdint 吗?
【发布时间】:2011-05-26 20:30:30
【问题描述】:

我一直在思考要不要使用<cstdint>里面的typedef。

我个人更喜欢写 uint32_t 而不是 unsigned intint8_t 而不是 char 等等...因为它对我来说更直观。

你们怎么看?使用 <cstdint> 的 typedef 是否是个好主意?有什么缺点吗?

【问题讨论】:

  • 这些类型不等价。
  • 首选使用 POD 类型,除非变量的大小对应用程序很重要。嵌入式系统以使用特定于大小的变量而闻名,而桌面应用程序则不太受关注。数据库应用程序可能需要特定大小的变量。
  • @Thomas: uint32_t 和朋友都是POD;它们是 typedef 继承自 C99。
  • @Thomas : POD 已经有了定义的含义;这些被称为“原始”或“基本”类型。
  • @ildjarn:我同意 POD 在这里不是正确的术语。但是,uint32_t 和朋友也是“原始”类型。我们可能需要像“经典”或“K&R”这样的术语来描述历史上可用的类型。

标签: c++ cstdint


【解决方案1】:

其实,我建议两者都用。

如果您想要绝对是 32 位无符号的,请使用 uint32_t。例如,如果您正在实现一个“结构”来表示一个外部对象,其规范将其字段之一定义为 32 位无符号。

如果您想要“机器的自然字长”,请使用 int 或 unsigned int。例如:

for (int i = 0 ; i < 200 ; ++i)
    // stuff

“机器的自然字长”将为您提供最佳性能,无论是在今天的处理器上还是在明天的处理器上。

如果您的意思是“字符”,请使用“char”;如果您的意思是“字节”,则为“char”或“unsigned char”。 C/C++ 允许您通过“char *”访问任意对象的字节,严格来说,不是其他任何东西。

如果您特别想要一个 8 位整数,请使用 uint8_t 或 int8_t,类似于 uint32_t。

【讨论】:

  • 不会使用 size_t 代替 int 或 unsigned int 作为机器的自然字长吗?
  • @MathieuJVL:取决于你所说的自然字长。一台机器可能在 32 位整数上运行速度最快,但具有 64 位指针,因此 size_t 必须大于 int
  • 在这种情况下,您实际上应该使用 uint_fast32_t。这被定义为至少 32 位宽的“最快”数据类型。不过,它比无符号更难输入。
  • 请注意,严格来说,所有intN_tuintN_t 类型都是可选的。例如,曾经有 36 位字的机器和CHAR_BIT == 9。对于这样的机器,没有 8 位类型,因此不会在它们上定义 uint8_t(但会定义 uint_least8_t,就像 uint_fast8_t 一样)。如今,此类机器主要是博物馆藏品,但另一种不提供uint8_t 的现代系统类型将是CHAR_BIT == 16 的DSP 芯片。
  • 好的答案,只是一个改进它的建议:如果你使用 int 而不是 unsigned 它不仅更短,而且更适合整数文字(因为这些是默认签名的) .这个建议对于在条件中使用 sizeof 会有所不同,但它不会显示何时使用“本机类型”。
【解决方案2】:

你应该同时使用。当您需要“大小合理”的整数时,您应该使用int,如其他答案中所述。当你需要一个角色时使用char:它是自我记录的。

在二进制与外界交互时应该使用uint32_t和朋友:在进行网络编程、处理二进制文件或使用外部多字节编码等时。在这些情况下,类型的确切大小至关重要编写正确的、可移植的、自记录的代码。这就是 &lt;stdint.h&gt;(或 C++0x &lt;cstdint&gt;)的用途。

(字节序同样重要,但这完全是另一回事。)

【讨论】:

  • +1 用于精确大小的类型和关于自记录编码的注释。
【解决方案3】:

这取决于变量的用途。

如果您需要循环计数器,请使用int。如果需要字符串,请使用 char 的数组。

如果您需要一个可以容纳 -1 到 100 的数值变量,int8_t 很好。如果您需要表示 0 到 100,000 之间的值,那么 uint32_t uint_least32_t(感谢@Serge)是一个很好的选择。

【讨论】:

  • "如果您需要表示 0 到 100,000 之间的值,那么 uint32_t 是一个很好的选择。"没有。uint_least32_t 是很好的选择。而long int 是不错的选择。 uint_least32_t 始终存在于兼容的实现中。 uint32_t 不需要实现(对于某些平台,可能无法有效地实现)。
  • 实际上uint32_t 用于如果您需要精确的尺寸类型。例如。如果您需要定义一个可移植的二进制结构(为二进制格式定义一些结构,如文件系统/数据库/多媒体容器、一些协议头等)。
  • "如果你需要一个可以容纳 -1 到 100 的数值变量,int8_t 很好。” 不是特别好。对于单个变量,int 可能会更好; int8_t 可能会节省 3 个左右的字节,但这种节省将被提取单个字节的性能影响所淹没,无论如何,该字节可能会提升为 int。如果你想学究气,可以使用intfast8_t,但实际上,只需使用intint8_t 如果您需要大量它们,可能会更好。
  • @Keith:对于本地(自动/堆栈)变量,int8_t 可能表现不佳。我打算用循环计数器示例来介绍这种情况。对于数据结构内的变量,int8_t 更好的缓存效率几乎总是能弥补提取单个字节的任何额外工作。
  • @Wolf:如果您的字符串不是 ANSI,请使用 UTF-8 并且“char 数组”仍然适用。
【解决方案4】:

需要使用来自 cstdint 的 typedef 的一种特殊情况是在处理执行大量指针到 int 转换的代码时,在这种情况下使用 intptr_t 是绝对的要求。

在我工作的公司中,我们正准备将自己从 32 位迁移到 64 位大量的劣质 C/C++ 代码,这些代码不断将指针转换为 int,然后再转换回指针,这在 64 位架构上肯定会失败,所以我们将尽可能地尝试清理代码(即修改数据结构和接口以完全消除强制转换的需要)并在其他任何地方使用 intptr_t 而不是 int。

附带说明:一般来说,强制转换应该引起怀疑,但说真的,将指针强制转换为整数几乎总是设计中某个地方存在严重缺陷的结果。基本上,每次您将指针隐藏在 int 后面时,您都是在对编译器、平台以及更重要的是您的同事撒谎。

除此之外,就像其他人所说的那样:尽可能使用泛型类型,并在需要时使用显式大小的类型。

【讨论】:

  • +1。虽然……从前,很久以前,“long”应该足够长,可以容纳指针;事实上,足够长的时间来保存任何有符号整数类型。然后“long long”出现并搞砸了。我多么渴望过去的日子......
  • @Nemo:不,拿着指针从来都不是long的目的。
  • @Ben:也许不是。但是从前,“long”应该是“最长的整数类型”,其语义与 intmax_t 没有什么不同。 (不,我没有参考资料。而且我并不是说这是标准的。但我确实记得当 GCC 首次引入“long long”时各种专家的色调和哭泣。)因此,如果任何指针都可以转换为int,也可以转换为 long...
  • @Nemo:最后一句话是正确的,因为根据定义sizeof (long) &gt;= sizeof (int)。但是将指针转换为非指针类型从来都不是可移植的。
  • 与其将代码更改为使用intptr_t(或uintptr_t),您是否可以更改代码使其根本不需要在指针和整数之间进行转换?如果需要泛型指针类型,可以使用void*
【解决方案5】:

您基本上似乎对 uint32_t 和 unsigned int 之间没有任何线索。这是完全正常的,因为您不一定知道以后将如何使用您的类型。

只需使用 typedef。

无论您需要 unsigned int 还是 uint32_t(您可以稍后想到,当您对您的程序有更完整的看法时),使用 typedef 将帮助您通过指定什么来使您的代码更清晰你真的在操纵,当你在几个月后发现你最初的选择是最糟糕的选择时,它会让你更容易改变到另一种类型。这里没有“正确答案”,因为您通常很难弄清楚这些事情。在需要 uint32_t 的库和需要 int 的其他库之间进行互操作是很痛苦的。

【讨论】:

  • 第一句话是无谓的侮辱。不过,这个答案的其余部分是相当合理的。
  • 这并不是侮辱性的。现在好些了吗?
  • 不幸的是它不是。 “你没有任何线索”是英语的惯用表达,意思是“你不知道你在说什么,你很愚蠢/没有受过教育/愚蠢。”我认为您的意思是“您还没有解释自己”,可以表述为“您没有提供任何线索”。有关更多详细信息,最好在英语用法子网站上提问。
【解决方案6】:

尽可能使用templates 和泛型编程。如果没有必要,不要依赖任何类型!

如果你有一个函数,它接受一个数字并返回它乘以 2,这样写:

template <typename Number>
inline Number doubleNum(Number n) {
  return 2*n;
}

甚至这个:

template <typename RetType, typename NumberType>
inline RetType doubleNum(NumberType n) {
  return 2*n;
}

这样,如果您有一个使用 ints、doubles、uint64_ts 的库 - 您可以命名它 - 您可以使用它,而无需重写代码。如果您需要使用二进制文件或网络编程,您可以使用固定大小的类型,而无需重写代码。如果您需要任意精度的数字,您可以使用通过运算符重载实现与原始整数或浮点类型相同接口的类,例如 GMP 包装器,无需重写代码。 p>

您可以专门化模板函数或类,以优化特定情况或使用不符合相关接口的类(或 C structs):

/*
 * optimization:
 * primitive integers can be bit-shifted left to
 * achieve multiplication by powers of 2
 * (note that any decent compiler will do this
 *  for you, behind the hood.)
 */
template <>
inline int doubleNum<int>(int n) {
  return n<<1;
}
/*
 * optimization:
 * use assembly code
 */
template <>
inline int32_t doubleNum<int32_t>(int32_t n) {
  asm {
    ...
  }
}
/*
 * work with awkward number class
 */
template <>
inline AwkwardNumber doubleNum<AwkwardNumber>(AwkwardNumber n) {
  n.multiplyBy(2);
  return n;
}

【讨论】:

    猜你喜欢
    • 2011-12-26
    • 2021-12-10
    • 2010-12-25
    • 2014-05-27
    • 2010-12-25
    • 2018-09-11
    • 2012-07-02
    • 2017-04-21
    • 2010-10-29
    相关资源
    最近更新 更多