`long`是否保证至少有32位?

53

根据我对C++标准的阅读,我始终理解C++中整数基本类型的大小如下:

sizeof(char) <= sizeof(short int) <= sizeof(int) <= sizeof(long int)

我从3.9.1/2中推断出以下结论:

  1. 有四种带符号整数类型:“signed char”,“short int”,“int”和“long int”。在此列表中, 每个类型提供的存储空间至少与在列表中其前面的类型一样多。普通的int类型具有由执行环境的体系结构建议的自然大小。

而且,3.9.1/中描述了char的大小:

  1. [...]足够大以存储实现的基本字符集中的任何成员。

1.7/1更明确地定义了这个概念:

  1. C++内存模型的基本存储单元是字节。一个字节至少足以包含基本执行字符集的任何成员,并由一系列连续的位组成,其数量是实现定义的。

这使我得出以下结论:

1 == sizeof(char) <= sizeof(short int) <= sizeof(int) <= sizeof(long int)
sizeof能告诉我们类型占用的字节数,但实现定义了每个字节占用的位数。大多数人可能习惯于处理8位字节,但标准规定每字节有个位。

此帖子中,Alf P. Steinbach说:

long至少保证为32位。


这与我对C++中基本类型大小详细了解的所有内容相矛盾。通常,我会将这种陈述视为新手的错误,但由于这是Alf说的,所以我决定进一步调查。

那么,你怎么看? 标准保证long至少为32位吗? 如果是,请具体说明如何做出此保证。 我就是看不到。

  • C++标准明确表示,要了解C ++,必须了解C(1.2 / 1)。
  • C ++标准隐含地定义了可容纳long的值的最小限制为LONG_MIN-LONG_MAX
因此,无论 long 多大,它都必须足够大,以容纳LONG_MIN到 LONG_MAX 。但Alf和其他人明确表示,long至少必须为32位。这就是我要证实的。C++标准明确指出,字节中的位数没有指定(可能是4、8、16或42)。那么从能容纳LONG_MIN-LONG_MAX到至少32位之间如何建立联系?
LONG_MIN -2147483647 // -(2^31 - 1)
LONG_MAX +2147483647 //   2^31 - 1

3
@Mark:确实有可以处理和使用超过8位的数量的机器,例如32位字,这时通常使用char == int == long == 32位。 - Yakov Galka
4
现在不是8位字节的情况已经很少见了,但过去有更多种类的系统。拥有36位字长的计算机将具有9位字节。如果CDC Cyber系统得到C编译器,拥有60位字长的系统将不得不使用60位字节(这会引起问题),但通常字符仅使用6位(如果确实需要小写,则有6/12位方案)。 - David Thornley
4
@Mark Storer:德州仪器有一系列带有C++编译器和16位字节的DSP,或者他们曾经有过,几年前。还有一种带有9位字节的时代陈旧的野兽,其起源可以追溯到中世纪。“Unisys”?不确定。如果你真的感兴趣,我可以查一下。干杯! - Cheers and hth. - Alf
2
嗯,我猜如果有人发明了一种方法,在少于32位的存储空间中存储(2^32)-1个不同的值,那么long类型可能就不会有32位了。然而,在任何二进制平台上,只要数学是有效的,你都会有32位。 - Anon.
2
@Alf:确实简洁明了。没错,正如本帖所示。然而,我建议您留下更多步骤,并在“C标准中如此规定”这种回答中更加礼貌。我也没有看到联系,所以我能理解他的困惑。 - John Dibling
显示剩余17条评论
5个回答

38

C++ 使用了 C 标准中定义的限制 (C++: 18.3.2 (c.limits), C: 5.2.4.2.1):

LONG_MIN -2147483647 // -(2^31 - 1)
LONG_MAX +2147483647 //   2^31 - 1

因此,您可以确保long至少为32位。

如果您想要遵循漫长曲折的路线来确定LONG_MIN/LONG_MAX是否可由long表示,则需要查看C++标准中的18.3.1.2(numeric.limits.members):

static constexpr T min() throw(); // Equivalent to CHAR_MIN, SHRT_MIN, FLT_MIN, DBL_MIN, etc.
static constexpr T max() throw(); // Equivalent to CHAR_MAX, SHRT_MAX, FLT_MAX, DBL_MAX, etc.

我将脚注移入评论中,因此它与标准中的内容不完全相同。但基本上意味着std::numeric_limits<long>::min()==LONG_MIN==(long)LONG_MINstd::numeric_limits<long>::max()==LONG_MAX==(long)LONG_MAX
因此,即使C++标准没有指定(有符号)负数的位表示,它必须是二进制补码并且需要总共32位存储空间,或者它具有显式符号位,这意味着它也需要32位存储空间。

3
如果你一路跟随那篇帖子中漫长的评论链,经历了所有人身攻击,大致上就能得到这个结果。很高兴看到它可以简洁地解释,而不用指责任何人。 - T.E.D.
1
在C++标准中哪里写明了long必须容纳值[LONG_MIN,LONG_MAX]?我找不到任何相关的参考。 - John Dibling
1
@pst: 请注意,限制值允许比那些值更大。符合规范的实现可以允许-2 ^ 31,也可以允许+2 ^ 31。 - Anon.
3
@John Dibling,这篇文章在C和C ++标准之间来回跳动。整数类型的大小部分来自C标准。即使在C++标准中,也有参考ISO C标准的内容,例如"参见:ISO C子类xxx"。 - wkl
1
@John,我编辑了我的评论,但是C++标准经常参考ISO C标准。C++03的附录C讨论了C和C++标准之间的兼容性/不兼容性,并且它们没有提到两者在类型宽度方面的任何差异。这与标准关于<climits>具有与<limits.h>相同内容(S 18.2.2)的说法结合起来,表明C标准中声明的类型宽度也适用于C ++。 - wkl
显示剩余11条评论

17
答案明确是YES。阅读我的原帖和所有评论以理解具体原因,但以下是简短版本。如果您对此有任何疑问或问题,请阅读整个线程和所有评论。否则请接受以下事实:
1. C++标准包括C标准的某些部分,包括LONG_MINLONG_MAX的定义。
2. LONG_MIN定义为不大于-2147483647
3. LONG_MAX定义为不小于+2147483647
4. 在C++中,整数类型在底层表示中以二进制存储。
5. 为了在二进制中表示-2147483647+2147483647,需要32位。
6. C++ long保证能够表示LONG_MINLONG_MAX的最小范围。
因此,long必须至少为32位1
编辑: LONG_MINLONG_MAX的值由C标准(ISO/IEC 9899:TC3)第§5.2.4.2.1节规定的大小决定:
“……它们的实现定义值的大小应等于或大于(绝对值)那些显示的值,并具有相同的符号……”
— minimum value for an object of type long int
LONG_MIN -2147483647 // -(2 ^ 31 - 1)
— maximum value for an object of type long int
LONG_MAX +2147483647 // 2 ^ 31 - 1

1 32位:这并不意味着sizeof (long) >= 4,因为一个字节不一定是8位。根据标准,一个字节是某个未指定的(平台定义的)位数。虽然大多数读者会觉得这很奇怪,但实际上有真正的硬件,其CHAR_BIT为16或32。


1
我被要求将这个作为一个独立的答案,因此当时间过去时我会接受它。 - John Dibling
1
有两个技术细节需要提到。首先,有符号范围是对称的(-2147483647 ... +2147483647而不是-214748364‌‌ 8 ... +2147483647),以允许有符号整数可能不使用二进制补码。最新的C和C++标准仍然认为这是一个现实可能性,尽管最后一台商用的非二进制补码机器在20世纪70年代就停产了(其中之一是UNIVAC系列,不确定具体是哪一款)。 (续) - zwol
1
其次,更重要的是,long 至少为 32 位并不意味着 sizeof(long) >= 4。实际上有些机器的 CHAR_BIT 是 16 或 32,因此 sizeof(long) 可能只有 2 或 1。与一补码主机和 9 位小型机不同,这些机器仍在生产中(据我所知)。它们大多是不寻常的微控制器。是的,使用它们有点麻烦。 - zwol
@Zack:关于你的第二点,我在原帖中确实说过:“此外,一个字节有多少位是由实现定义的。我们大多数人可能习惯于处理8位字节,但标准规定一个字节有n位。”不过我猜这个信息有点被埋没了,因此在回答中更明确地提到它会更有用。 - John Dibling
@zwol:如果标准允许这样做,将LONG_LONG_MIN设为-0x7FFF000000000000可能会带来实际优势,使得所有形如0x8000xxxxxxxxxxxx的有符号数都表现为NaN,并且因此可以用于溢出捕获(如果唯一的NaN是0x8000000000000000,则产生溢出的代码需要在处理上位比特之后重新处理下位比特以存储NaN值;扩展NaN范围将允许16位机器在担心结果的上位比特应该产生数字还是NaN之前对“long long”的下位比特进行数学运算。 - supercat
显示剩余2条评论

7
但 Alf 和其他人明确表示 long 必须至少为 32 位。这就是我试图建立的内容。C++ 标准明确指出字节中的位数未指定。可能是 4、8、16、42……那么如何从能够容纳 LONG_MIN-LONG_MAX 的数字到至少 32 位之间建立连接呢?
您需要在值表示中使用 32 位才能获得至少这么多个比特模式。由于 C++ 要求整数具有二进制表示(标准中有明确的语言表述,§3.9.1/7),因此 Q.E.D.

为什么你会这样说,因为需要许多位模式吗?在你能写下“Q.E.D.”之前,你必须添加很多步骤。 - Mooing Duck
@MooingDuck:不,使用普通算术没有中间步骤。问题是“如何建立连接”,并且它是这样的:2^n = M 直接给出 n = log2(M)。看,没有中间步骤。好吧,除非你想在没有log2按钮的计算器上计算它。然后 log2(M) = ln(M)/ln(2)。 :-) - Cheers and hth. - Alf

7

C++标准指出,<climits>的内容与C头文件<limits.h>相同(参见ISO C++03 doc的18.2.2)。

不幸的是,我没有一份C++98之前存在的C标准副本(即C90),但在C99(第5.2.4.2.1节)中,<limits.h>必须具有至少这些最小值。 我认为这与C90无异,除了C99添加了long long类型。

— minimum value for an object of type long int

LONG_MIN -2147483647 // −(2^31 − 1)

— maximum value for an object of type long int

LONG_MAX +2147483647 // 2^31 − 1

— maximum value for an object of type unsigned long int

ULONG_MAX 4294967295 // 2^32 − 1

— minimum value for an object of type long long int

LLONG_MIN -9223372036854775807 // −(2^63− 1)

我也没有C标准(我是一个C++程序员)。但是让我们假设你发布的内容适用于C++。我正在尝试连接C标准和C++标准之间的关系,并最终确定一系列参考文献,这些参考文献明确指出long至少必须为32位。让我们简化一下,可以说long必须至少容纳LONG_MIN-LONG_MAX范围。 - John Dibling
@John - 我认为这个讨论将在MSN的回答中继续,所以我认为所有好的答案都会在那里。 - wkl

7

是的,C++标准明确规定字节中的位数未指定。长整型的位数也未指定。

设置数字的下限并不等同于指定它。

C++标准在一个地方说:

1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long).

这实际上意味着,在另一个地方,通过包含C标准:

CHAR_BITS >= 8; SHORT_BITS >= 16; INT_BITS >= 16; LONG_BITS >= 32

(除了我所知道的,SHORT_BITS、INT_BITS和LONG_BITS这些标识符不存在,并且这些限制是通过类型最小值的要求推断出来的。)
这是因为在数学上需要一定数量的位来编码(例如对于longs)LONG_MIN..LONG_MAX范围内的所有值。
最后,shorts、ints和longs必须由整数个字符组成; sizeof()总是报告一个整数值。此外,逐个字符地迭代访问内存必须访问每个位,这会带来一些实际限制。
这些要求在任何方面都不矛盾。满足要求的任何大小都可以。
很久以前有一些本地字长为36位的机器。如果你要将C++编译器移植到它们上面,你可以合法地决定char中有9位,在short和int中各有18位,在long中有36位。你也可以合法地决定在这些类型中每个都有36位,原因与今天典型的32位系统上int有32位一样。有使用64位字符的实现。
请参阅C++ FAQ Lite的26.1-6和29.5章节。

没错,但我的问题是长整型必须至少为32位,而不是恰好32位。 - John Dibling
答案是“是的,'至少'”。在我的回答中,值是以下限而不是精确数量指定的(除了 sizeof(char),因为就C++而言,char 就是字节,但字节不一定是八位字节)。因为这就是标准规定的方式。 - Karl Knechtel

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