2014-09-30 59 views
3

Shell Arithmetic说:bash中固定宽度整数的宽度是多少?

评价以固定宽度的整数进行,不检查是否溢出,虽然 除以0被捕获并标记为错误。

实施例:

$ echo $((1 << 32)) 
4294967296 
$ echo $(((1 << 64) - 1)) 
0 

什么是壳算术整数限制在bash?

@rici pointed outPOSIX shell保证签订长期整数的范围(由ISO C定义):

-2**31+1 to +2**31-1 

@John Zwinck pointed outbash source code indicates that intmax_t is used

所有算术作为intmax_t整数完成没有检查溢出

bash保证在其文档它使用intmax_t或其他一些C类型的整数?

+0

我不认为在飞越(!)后减1(!)将有助于:-)尝试echo $(((1 << 63) - 1)).. 9223372036854775807 – 2014-09-30 13:09:11

+0

@MarkSetchell:关键是我的机器上有'1 << 64'溢出。在这种情况下结果并不重要。 – jfs 2014-09-30 13:10:14

+1

我曾幻想你在做一个二进制搜索以找到没有溢出的移位... << 48,<< 56,<< 60, – 2014-09-30 13:12:18

回答

2

Bash没有记录整数的确切大小,并且大小可能因平台而异。

但是,它确实试图符合Posix,它指定算术扩展使用带符号的长算术,它必须至少包含32位(包括符号位)。

的Posix不需要整数运算是模2 ķk任何值,但见注1],虽然bash共同平台将这样做,而且特别不保证算术运算符的行为完全就好像这些值是经过长时间签名的。 Posix甚至允许使用浮点模拟整数运算,前提是浮点值具有足够的精度:

作为扩展,shell可以识别超出列出的算术表达式。 shell可能使用一个有符号整数类型,其排名大于signed long的排名。在没有溢出的情况下,只要不影响结果,shell可以使用真实浮点型而不是长整型。 (XSH § 2.6.4)

这将允许一个平台,long仅为32位,例如在使用IEEE-754浮点数的加倍(精度53位)。虽然bash不这样做 - 正如文档中所述,bash使用固定宽度的整数数据类型 - 其他shell实现可能会和可移植代码不应做出假设。


注:

  1. 的Posix通常推迟到ISO C标准,但也有一些地方的Posix增加了一个附加的约束,其中的一些被标记为扩展(CX):

    POSIX.1-2008部分地作为ISO C标准的一部分,它可以选择进一步构建ain行为允许根据ISO C标准而变化。即使缺少CX标记,这些限制和其他兼容差异也不会被视为冲突。标记仅供参考。

    其中一个附加约束是存在精确宽度的整数类型。标准C要求类型int_{least,fast}{8,16,32,64}_t及其无符号类似物。它不需要精确宽度类型,例如int32_t,除非某些整数类型符合要求。精确宽度类型必须正好具有其名称中指示的位数(即没有填充位),并且必须具有2的补码表示。因此INT32_MIN,如果已定义,则必须正好-2 (§ 7.20.2.1)。

    然而,Posix的确实需要的确切宽类型int{8,16,32}_t(以及无符号类似物),并且也int64_t如果这样的类型是由实现提供。特别是,如果“实现支持_POSIX_V7_LP64_OFF64编程环境并且应用程序正在编程环境中构建,则需要int64_t”。 (XBD,§ 13,stdint.h)(这些要求都被标记为CX。)

    尽管int32_t必须存在,因此必须有一些2的补码型可用的事实,但仍然没有保证signed long是2的补码,即使是这样,也不能保证整数溢出回绕,而不是例如陷阱。

    最为相关的原题,虽然是事实,即使signed long是同一类型int64_t即使有符号整数溢出环绕,外壳是没有根据实际使用signed long的算术扩展的任何义务。它可以使用任何数据类型“只要在没有溢出的情况下不影响结果”。 (XSH,§ 2.6.4)

+0

对于提及**签名的POSIX shell的long **限制+1。 [posix](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04)显式遵循整数算术的ISO C标准(与** signed long ** ISO C相同)。它是ISO C,不需要模块2 ** k算术,而不需要posix。 – jfs 2014-10-01 10:10:02

+0

@ J.F.Sebastian:Posix可以自由地要求二进制补码算术。例如,它需要8位字节,所以它非常需要标准C没有的东西。所以我支持我的声明,Posix不需要2s补码。但更重要的一点是下一句:Posix并不要求shell甚至在该平台上遵循已签名longs的行为,因为它(明确地)允许使用浮点,而浮点的精度至少与一个长签名。 – rici 2014-10-01 16:36:40

+0

@JFSebastian:为了证明这个过长的帖子包含了对“在文档中是否保证保证......”这个问题的回答(即“没有,没有改变任何文本)没有保证。“)我通过对bashref.texi进行了几处关键词的验证来验证我对该手册的阅读情况,所以我准备用一个明确的”不“号出现在肢体上。当然,截至今天这是真的(v4.3.25);文档可能随时改变。 – rici 2014-10-02 20:15:11

1

Bash在其C算法实现中使用intmax_t。你可以在这里看到它:http://www.opensource.apple.com/source/bash/bash-30/bash/expr.c

这意味着它将是您的平台上的“最大”整数类型。请记住,某些平台具有“更大”的整数,例如一些64位平台上的128位整数,但这些“非凡”类型不包括在内,所以大多数系统现在会看到Bash使用32位或64位数学运算。

+0

[当前源码](http://git.savannah.gnu .org/cgit/bash.git/tree/expr.c#n22)也确认使用了'intmax_t'。它在文档中的某处提到过吗? – jfs 2014-09-30 14:13:05

+0

我还没有找到它在(非源代码)文档中的任何地方。某种程度上可能被认为是实施细节。我认为这不是那么重要,因为它在源代码本身中有非常清晰的记录;我想你可以提交一个文档补丁。 – 2014-09-30 14:16:27