【问题标题】:How do I ask for "at least" a size of an int in C我如何在 C 中要求“至少”一个 int 的大小
【发布时间】:2014-09-12 00:42:33
【问题描述】:

情况:

我有一个用 C 语言编写的应用程序,它是资源密集型的,并且设计为可移植的。我想让编译器为架构选择最快的 int 大小,前提是它至少为 32 位。

是否可以选择“至少”32 位的大小,或者编译器会自动优化这些东西吗?

【问题讨论】:

  • 为什么是 C++ 标签?是否需要 C++ 兼容性?
  • 我认为这就是long 的用途。
  • 你正在寻找stdint.h typedefs,比如int_least32_t
  • @Quentin:不,不是。
  • @Quentin:标准在哪里保证,long 始终是架构中最快的整数类型?

标签: c++ c optimization


【解决方案1】:

标准标头stdint.h 提供int_leastN_tuint_leastN_t 类型,其中N 是8、16、32 和64(可能还有其他,但这些不是必需的)。这些是 C99 的标准。

它还提供“快速”替代方案,即int_fastN_tuint_fastN_t,具有相同的N 值。

因此,在您的情况下,您可以使用int_least32_tint_fast32_t

【讨论】:

  • int_fast32_t 是 OP 在这里需要的。 int_least32_t 不是 32 位以上的最快整数类型,只是最小的。
  • 谢谢,这正是我想知道的。
  • 除了 int_fast32_t 在 x86_64 这样的重要架构上被错误定义,它实际上是 慢得多 类型(64 位而不是 32 位):对于 +/ -/* 两者的速度相同,但对于 / 来说速度要慢得多,当然加载/存储速度也更慢,因为您使用了两倍的缓存线和两倍的内存带宽。所以我真的很犹豫要不要使用它。我不知道 any 具有 32 位 int 的拱门,它不是处理“至少 32 位”整数的最快类型。
  • @R..:short 不应该同样如此吗?即短裤的划分不应该更快(假设它们实际上更小并且C没有自动将它们提升为int)?
  • @Mehrdad:可能,但通常在短裤上加载/存储和执行操作的额外成本。在一些旧的 x86 上,操作数大小前缀阻止了流水线;也许现在唯一的成本是增加指令缓存的使用。当然,这是“快速”类型被误导的另一个原因——哪种类型更快很可能取决于特定的 cpu 模型,而不仅仅是 ISA。而且您实际上不能根据-march 或其他什么来更改类型,因为这会破坏 ABI。
【解决方案2】:

这个问题也被标记为 C++,所以这里是像我这样的模板元编程爱好者的解决方案。

要求

  • 类型列表类型,此处命名为list
  • 类似 Haskell 的 filter 元函数。
  • head 元函数,用于获取类型列表的第一个元素。

代码

此解决方案自动执行已接受的解决方案(即“转到stdint.h 并选择最适合您的解决方案”)。那项工作可以由编译器完成,不是吗?

首先列出在<cstdint> 声明的所有特定于平台的最快整数类型:

using integer_types = list<std::int_fast8_t,std::int_fast16_t,
                           std::int_fast32_t,std::int_fast64_t>;

请注意,列表是按整数大小递增排序的。
现在定义一个过滤谓词。在我们的例子中,大小应该小于用户指定的大小(命名为SIZE):

template<typename T>
using f = std::integral_constant<bool,sizeof(T)*CHAR_BITS <= SIZE>;

然后过滤整数类型列表,得到结果的第一个元素:

using best_integer_t = head<filter<f,integer_types>>;

总结解决方案

template<std::size_t SIZE>
struct fastest_integer_impl
{
    //Guard for the case the user specified less than one byte size:
    static constexpr const std::size_t size = SIZE >= CHAR_BITS ? size : CHAR_BITS;

    using integer_types = list<std::int_fast8_t,std::int_fast16_t,
                               std::int_fast32_t,std::int_fast64_t>;

    template<typename T>
    using f = std::integral_constant<bool,sizeof(T)*CHAR_BITS <= size>;

    using type = head<filter<f,integer_types>>;
};

template<std::size_t SIZE>
using fastest_integer = typename fastest_integer_impl<SIZE>::type;

【讨论】:

  • 不会fastest_integer&lt;4&gt; 给出与std::int_fast32_t 相同的值吗?这比直接使用std::int_fast32_t 有什么好处?
  • @PeterSW 抱歉,是实施中的拼写错误。元函数应该以位为单位工作。元函数的重点是使整数选择过程自动化。像 “我正在使用 20 位,您拥有的最快的整数类型是什么?”
  • 感谢一些 C++ :)
【解决方案3】:

正如其他人所指出的,标准包含文件定义了int_fast32_tint_least32_tuint_fast32_tuint_least32_t,它们的行为可能会如您所愿,但使用此类类型时需要格外小心。由于整数提升规则,C 代码无法避免使用类型intunsigned int。此外,整数文字可能并不总是属于人们所期望的类型。例如,int_fast32_T 与文字 0xABCD123412345u 之间的比较可以作为有符号或无符号执行,具体取决于 int 是 16 位、32 位还是 64 位。同样,如果 n 是 32 位或更大,n &amp;= ~0x8000; 的含义在 16 位机器上与在更大的机器上会有所不同。

C 标准从未专门设计用于方便编写关心整数大小的代码,但仍可在不同大小的硬件上兼容工作。像int_fast32_t 这样的类型可以轻松编写看起来应该是可移植的代码,但可能会鼓励人们对隐藏在语言中的所有讨厌的小陷阱感到自满。

【讨论】:

    【解决方案4】:

    最快 => 使用编译指示包与架构对齐。如果没有这个,如果内存没有对齐,则需要不止一次的内存访问。

    min 32 => 使用 int 说明符 - 足够了。据我所知,这确保了 linux 中所有架构的 32 位。

    【讨论】:

    • 其实恰恰相反。 pragma pack导致错位,因为它会阻止编译器插入保持数据对齐所需的填充。
    • 他说“便携”;不能假设linux。 16 位系统现在确实很少见,但我认为你不能排除它们,除非问题确实如此。
    • 不知道我是如何发布这样一个答案的。我想,我一定是错误地为错误的问题发布了这个答案。
    猜你喜欢
    • 1970-01-01
    • 2019-05-15
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 2020-03-08
    • 1970-01-01
    • 1970-01-01
    • 2021-01-26
    相关资源
    最近更新 更多