在c99中很长很长
Long long in c99
他们在 C99 标准中引入了 long long
。这样做的目的是什么?在我(有限的)C 编程经验中,我只见过一个 4 字节的 int 和一个 8 字节的 long。例如,从编译器资源管理器:
如果long
已经是8
那么,为什么还要添加另一个long long
类型呢?这对 compiler/architecture 有什么影响?
C标准只保证一个int
可以是(松散的)2个字节,一个long
可以是4个字节,一个long long
可以是8个字节。
事实上,MSVC 仍然使用 4 字节 long
,即使它有 4 字节 int
。
If long is already 8 then, why is it necessary to add another long long type? What does this do to the compiler/architecture?
“如果 long 已经是 8”并不总是正确的,因为存在许多依赖 32 位 long
和 int
作为 32 或 16 位的代码。
要求 long
作为 64 位会破坏代码库。这是一个主要问题。
然而,要求 long
保持 32 位(而不是 long long
)将无法访问标准的 64 位整数,因此 long long
的基本原理。
允许 long
作为 32 位或 64 位(或其他)允许转换。
各种函数像fseek(), ftell()
一样传递in/returnlong
。他们受益于 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
, (u
)intmax_t
并留下 signed char
, (unsigned
) short
, (unsigned
) long
, (unsigned
) long long
用于特殊情况。
当时和现在 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 允许一个补码和 sign/magnitude 有符号整数,而不仅仅是 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,例如 Windows x64 和 32 位 long
不是那样的。
C99 int_fast32_t
和 x86-64 系统 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 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 不能小于 int。但可以肯定的是,到 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 转换为变量类型)。 solution/workaround 是一种让 is 免于发疯并保持语言活力的方法。
作者经常会选择,比如GPRs是16位就int是16位,32位就是32位等等,但是他们有一定的自由度。
是的,这具体意味着没有理由假设针对特定目标(例如您正在阅读本文的计算机)的任何两个工具对 int 和 long 使用相同的定义,特别是如果您想为这个平台编写可以跨这些工具(支持这个平台)的代码,然后使用 stdint.h 类型而不是 int、long 等......如果你跨平台 msp430 mcu,最肯定的是arm mcu,一个 arm linux 机器,一个基于 x86 的机器,即使对于相同的“工具链”(例如 gnu gcc 和 binutils),类型对 int 和 long 等的定义也不相同。 char 和 short 往往是 8 位和 16 位,int 和 long 往往变化最大,有时大小相同有时不同,但重点是不要假设。
对于编译器 version/target/command 行选项,检测大小是微不足道的,或者只是走 stdint 路线以尽量减少以后的问题。
他们在 C99 标准中引入了 long long
。这样做的目的是什么?在我(有限的)C 编程经验中,我只见过一个 4 字节的 int 和一个 8 字节的 long。例如,从编译器资源管理器:
如果long
已经是8
那么,为什么还要添加另一个long long
类型呢?这对 compiler/architecture 有什么影响?
C标准只保证一个int
可以是(松散的)2个字节,一个long
可以是4个字节,一个long long
可以是8个字节。
事实上,MSVC 仍然使用 4 字节 long
,即使它有 4 字节 int
。
If long is already 8 then, why is it necessary to add another long long type? What does this do to the compiler/architecture?
“如果 long 已经是 8”并不总是正确的,因为存在许多依赖 32 位 long
和 int
作为 32 或 16 位的代码。
要求 long
作为 64 位会破坏代码库。这是一个主要问题。
然而,要求 long
保持 32 位(而不是 long long
)将无法访问标准的 64 位整数,因此 long long
的基本原理。
允许 long
作为 32 位或 64 位(或其他)允许转换。
各种函数像fseek(), ftell()
一样传递in/returnlong
。他们受益于 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
, (u
)intmax_t
并留下 signed char
, (unsigned
) short
, (unsigned
) long
, (unsigned
) long long
用于特殊情况。
当时和现在 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 允许一个补码和 sign/magnitude 有符号整数,而不仅仅是 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,例如 Windows x64 和 32 位 long
不是那样的。
C99 int_fast32_t
和 x86-64 系统 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 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 不能小于 int。但可以肯定的是,到 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 转换为变量类型)。 solution/workaround 是一种让 is 免于发疯并保持语言活力的方法。
作者经常会选择,比如GPRs是16位就int是16位,32位就是32位等等,但是他们有一定的自由度。
是的,这具体意味着没有理由假设针对特定目标(例如您正在阅读本文的计算机)的任何两个工具对 int 和 long 使用相同的定义,特别是如果您想为这个平台编写可以跨这些工具(支持这个平台)的代码,然后使用 stdint.h 类型而不是 int、long 等......如果你跨平台 msp430 mcu,最肯定的是arm mcu,一个 arm linux 机器,一个基于 x86 的机器,即使对于相同的“工具链”(例如 gnu gcc 和 binutils),类型对 int 和 long 等的定义也不相同。 char 和 short 往往是 8 位和 16 位,int 和 long 往往变化最大,有时大小相同有时不同,但重点是不要假设。
对于编译器 version/target/command 行选项,检测大小是微不足道的,或者只是走 stdint 路线以尽量减少以后的问题。