2014-09-30 88 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