如何解决长长在 c99
在 C99 标准中,他们引入了 long long
。这样做的目的是什么?在我(有限的)C 编程经验中,我只见过 4 字节的 int 和 8 字节的 long。例如,从编译器资源管理器:
如果 long
已经是 8
,为什么还需要添加另一个 long long
类型?这对编译器/架构有什么影响?
解决方法
如果 long 已经是 8 了,那为什么还要再添加一个 long long 类型呢?这对编译器/架构有什么影响?
“If long is already 8”并不总是正确的,因为存在依赖 32 位 long
和 int
作为 32 或 16 位的代码。
要求 long
为 64 位会破坏代码库。这是一个主要问题。
然而,要求 long
保持 32 位(并且没有 long long
)无法访问标准的 64 位整数,因此是 long long
的基本原理。
允许 long
作为 32 位或 64 位(或其他)允许转换。
各种函数传入/返回long
,如fseek(),ftell()
。他们受益于 long
超过 32 位的大文件支持。
推荐的做法鼓励更广泛的 long
:“用于 size_t
和 ptrdiff_t
的类型的整数转换等级不应大于
signed long int
除非实现支持足够大的对象以使其成为必要。”这与超过 32 位的内存大小有关。
也许未来的实现可能会使用 int/long/long long/intmax_t
作为 32/64/128/256 位。
IAC,我看到固定宽度类型 intN_t
比 long
和 long long
更受欢迎。我倾向于使用固定宽度类型或 bool
,(unsigned
) char
,int
/unsigned
,size_t
,({{1} })u
离开intmax_t
,(signed char
) unsigned
,(short
) unsigned
,(long
) {{ 1}} 用于特殊情况。
C 标准仅保证 int
可以(粗略地说)2 个字节,long
可以是 4 个字节,long long
可以是 8 个字节。
事实上,MSVC 仍然使用 4 字节的 long
,即使它有一个 4 字节的 int
。
当时和现在对 int
和 long
的唯一相关要求是 int
必须至少为 16 位,而 long
必须至少为 32 位。 16 位和 32 位系统都倾向于使用 32 位 long
,而 64 位机器在 1990 年代后期并不常见。因此,在 C99 之前,程序员根本无法轻松地依赖 64 位整数类型可用。通过引入 long long
解决了这个问题,它要求至少为 64 位。 (我相信它已经由 GCC 和其他编译器作为扩展提供了)。
如今,许多(但不是全部)64 位系统使用 64 位 long
并且不费心使 long long
变得更大,所以它是64 位也是如此,并且在某种意义上是多余的。这些大概是您熟悉的系统,但它们并不代表所有的东西。
我认为您没有意识到您对 C 类型宽度要求的工作方式做出了一个巨大的错误假设:ISO C 只是设置了一个最小值范围,例如允许的最小幅度LONG_MAX
和 LONG_MIN
(-2147483647,不是 8,因为 ISO C 允许一个的补码和符号/大小有符号整数,而不仅仅是 2 的补码。)实际实现允许有更广泛的类型,通常是匹配目标机器可以有效执行的寄存器宽度或操作数大小。
在 Stack Overflow 和其他地方已经写了很多关于这个的文章,我不打算在这里重复。另见https://en.cppreference.com/w/c/language/arithmetic_types
我认为,这导致您错误地查看了 x86-64 System V ABI 中的类型宽度选择并假设其他 C 实现是相同的。 x86-64 是一种 64 位 ISA,可以有效地处理 64 位整数,因此 64 位 long
是一个相当明智的选择。
对于像 i386 这样的 32 位机器,没有健全的 ABI 会使用 64 位 long
,因为这不是必需的,只有 32 位。使用 64 位意味着它无法放入单个寄存器中。 使用 -m32
编译,或为 32 位 ARM 编译。 Godbolt 还具有用于 AVR 和 MSP430 的 GCC。在那些 8 位和 16 位机器上,GCC 选择 ISO C 允许的最小宽度(2 字节 int
等)
在 1999 年,x86-64 甚至不存在。 (其他一些 64 位 ISA 也这样做了,比如 Alpha)。因此,查看 2 个主流 ABI 之一以了解 C99 选择不会让您走得太远。
当然,C 需要一种保证至少为 64 位的类型,以便人们编写可以高效执行 64 位整数数学运算的程序。
顺便说一句,x86-64 可以像 64 位一样有效地处理 32 位整数,有时更有效。因此,将 long
设为 64 位类型可能不太好。一些代码使用 long
是因为他们想要一个需要是 32 位的类型,但不会因为它更宽而受益。对于此类代码,64 位 long
只会浪费缓存占用空间/内存带宽和代码大小(REX 前缀)。在 C99 中,理想的选择是 int_least32_t
,但这很烦人而且很少使用。
但是 OTOH,long
有时被希望成为“最广泛有效的(1 个寄存器)类型”,尽管没有这样的保证,并且 LLP64 ABI(例如具有 32 位 long
的 Windows x64)不是'不喜欢那样。
另一个完整的蠕虫是 C99 int_fast32_t
和 x86-64 System V 的 IMO 糟糕的选择,使其成为 64 位类型。 (我对 Cpp uint32_fast_t resolves to uint64_t but is slower for nearly all operations than a uint32_t (x86_64). Why does it resolve to uint64_t? 有一个写了一半的答案,我应该完成... int_fast32_t
提出了“为了什么目的而快速”的问题,并且在许多实现中这不是您希望的案例。
另见
- C++ - the fastest integer type?
- How should the [u]int_fastN_t types be defined for x86_64,with or without the x32 ABI?
- Why would uint32_t be preferred rather than uint_fast32_t?
- Why is uint_least16_t faster than uint_fast16_t for multiplication in x86_64?
- Compiler optimizations allowed via "int","least" and "fast" non-fixed width types C/C++
有一些限制,但编译器作者可以自由选择标准 C 变量类型(char、short、int、long、long long)的长度。自然 char 将成为该体系结构的一个字节(大多数 C 编译器是 8 位)。自然你不能让更小的东西比更大的东西更大,long 不能小于一个整数。但可以肯定的是,到 1999 年,我们看到了 x86 16 位到 32 位的转换,例如 int 从 16 位变为 32 位并使用了许多工具,但长期保持为 32。后来发生了 32 位到 64 位的 x86 转换,根据工具的不同,有可用的类型提供帮助。
问题早在此之前就存在了,解决方案不是固定类型的长度,在规则范围内,它们的大小取决于编译器作者。但是编译器作者需要制作一个与工具和目标匹配的 stdint.h 文件(stdint.h 至少是特定于工具和目标的,并且可以是该工具的工具版本和构建选项等)。因此,例如, uint32_t 始终为 32 位。一些作者会在他们的 stdint.h 中将其转换为 int 其他的 long 等。 C 语言变量类型仍然限制为每个语言的 char、short、int 等(uint32_t 不是变量类型,它通过 stdint.h 转换为变量类型)。这个解决方案/变通方法是一种防止一切变得疯狂并保持语言活跃的方法。
作者经常会选择例如 GPR 是 16 位让 int 是 16 位,如果 32 位是 32 位等等,但他们有一些自由。
是的,这特别意味着没有理由假设针对特定目标(例如您正在阅读本文的计算机)的任何两个工具对 int 和 long 使用相同的定义,特别是如果您想为这个平台编写可以跨这些工具(支持这个平台)移植的代码,然后使用 stdint.h 类型而不是 int、long 等...... arm linux 机器,一种基于 x86 的机器,类型,即使对于相同的“工具链”(例如 gnu gcc 和 binutils),对于 int 和 long 等的定义也不相同。 char 和 short 往往是 8 和16位,int和long往往变化最大,有时大小相同有时不同,但重点是不要假设。
对于编译器版本/目标/命令行选项而言,检测大小很简单,或者只是使用 stdint 路由以最大程度地减少以后的问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。