如何在C语言中请求至少一个int的大小

57

情况:

我有一个用C语言编写的应用程序,它需要占用大量资源,并且设计成可移植的。我希望允许编译器选择适合该架构最快的int大小,前提是它至少为32位。

是否可能选择至少32位的大小,或者编译器会自动为我优化这些内容?


11
为什么要加上C++标签?是否需要兼容C++? - Niall
5
我认为这就是“长”的意思所在。 - Quentin
26
您正在寻找类似于int_least32_tstdint.h类型定义。 - toasted_flakes
7
@Quentin:不,不是。 - Kaiserludi
2
@Quentin:标准在哪里保证long总是架构中最快的整数类型? - Kaiserludi
显示剩余4条评论
4个回答

92
标准头文件 stdint.h 提供类型 int_leastN_tuint_leastN_t,其中 N 可以是 8、16、32 和 64(也可能有其他值,但不是必需的)。这些类型自 C99 标准开始就被定义了。
它还提供了“快速”替代类型,即具有相同 N 值的 int_fastN_tuint_fastN_t
因此,在您的情况下,可以使用 int_least32_tint_fast32_t

34
OP 需要使用 int_fast32_tint_least32_t 不是速度最快的 32 位整数类型,只是最小的类型。 - TonyK
1
谢谢,这正是我想知道的。 - derekdreery
3
在一些重要的架构中(例如 x86_64),int_fast32_t 的定义是错误的,它实际上是一种更慢的类型(64 位而非32位):对于 +/ -/ *,两者速度相同,但对于 /来说它会慢得多,并且当然,由于使用了两倍的缓存行和两倍的内存带宽,加载/存储的速度也会变慢。因此,我非常不愿意使用它。我不知道有任何一种架构可以使用32位整型以外的最快数据类型处理“至少32位”的整数。 - R.. GitHub STOP HELPING ICE
@R..:short也应该是一样的,对吧?也就是说,如果它们实际上更小,并且C没有自动将它们提升为int,那么short的除法应该更快,对吗? - user541686
@Mehrdad:可能会有额外的成本用于加载/存储并执行shorts上的操作。在一些旧的x86 CPU上,操作数大小前缀阻止了流水线;现在唯一的成本可能就是增加了指令缓存使用率。当然,这是“快速”类型被误导的另一个原因,哪种类型更快很可能取决于特定的CPU型号,而不仅仅是ISA。你不能实际上让类型根据“-march”或某些其他东西变化,因为那会破坏ABI。 - R.. GitHub STOP HELPING ICE
@R..:感谢您提供的额外信息,感觉它应该成为一个独立的答案。如果你真的想要优化,似乎总是有许多复杂的层次。您还暗示了必须涉及缓存管理,可能包括汇编语言,以获得良好的优化效果,并且这将比类型宽度带来更大的差异? - derekdreery

20
正如其他人所指出的,标准的包含文件定义了int_fast32_t、int_least32_t、uint_fast32_t和uint_least32_t等类型,这些类型可能是您想要的,但是必须非常小心地使用。由于整数提升规则,C代码无法避免使用int和unsigned int类型。此外,整数字面量可能并不总是预期的类型。例如,在int_fast32_T和字面量0xABCD1234或12345u之间进行比较可能会根据int是16位、32位还是64位而被执行为有符号或无符号。同样,如果n是32位或更大,则在16位机器上执行n &= ~0x8000;的含义与在更大机器上执行n &= ~0x8000;的含义不同。
C标准从未特别设计用于方便编写关注整数大小的代码,但仍可在具有不同大小硬件的情况下兼容工作。像int_fast32_t这样的类型使得编写看起来应该是可移植的代码变得容易,但可能会鼓励对语言中隐藏的所有令人讨厌的小陷阱产生满足感。

10
这个问题也被标记为C++,所以这里有一个针对像我一样喜欢模板元编程的解决方案。

要求

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

代码

这个解决方案自动化了已接受的解决方案(即“转到并选择最适合您的”)。编译器可以完成这项工作,不是吗?

首先列出在<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;

8
“fastest_integer<4>”是否会与“std::int_fast32_t”给出相同的结果?这种方式比直接使用“std::int_fast32_t”有何优点?请简化表述,但不要改变原意。 - PeterSW
1
@PeterSW 抱歉,实现中有个打字错误。元函数应该使用位大小工作。元函数的目的是自动化整数选择过程。就像“我正在使用20位,你们至少有哪种最快的整数类型?” - Manu343726
1
谢谢你的一些C++ :) - derekdreery

-5

最快 => 使用#pragma pack对齐架构。如果不对齐内存,则可能需要多次内存访问。

最小32 => 使用int说明符 - 足够了。据我所知,这可以确保在Linux上跨所有架构使用32位。


7
实际上恰恰相反。pragma pack会导致数据不对齐,因为它阻止了编译器插入必要的填充以保持数据对齐。 - Mysticial
他说“可移植性”,不能假设是Linux。虽然16位系统现在很少见,但我认为除非问题实际上说明了这一点,否则不能排除它们的可能性。 - David Gelhar
不知道我怎么会发布这样的答案。我想我一定是错了题目,误发了这个答案。 - sudhakar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接