十進数だろ JK
はじめに
C/C++ で 0
と書くと八進数として解釈されるため、十進数のゼロを書くことはできないという小ネタがありますが、では他の言語ではどうだろうと気になりうっかり調べてしまったので記事にしました。
まあ八進数だろうが十進数だろうが処理系の気持の話でしかなく何かが変わるというものでもありませんが……
結果
概要
大まかに以下のグループに分けられました。
- 八進数として解釈される
- 十進数として解釈される (
0
始まりの八進数リテラルもある) - 十進数として解釈される (
0o
始まりの八進数リテラルしかない) - 十進数として解釈される (そもそも八進数リテラルがない)
この他、 0
始まりの八進数リテラルがあるものの 0
が八進数扱いなのか十進数扱いなのか調べても分からなかったものもありました。
結果一覧
- [2021-03-04 訂正: Go を
0o
始まりの八進数しかないグループに分類していましたが、0
始まりの八進数もあるとの指摘を受けて訂正しました] - [2021-03-04 訂正: JIS 規格には記述があるとの情報を受けて Ruby を不明から十進数に分類し直しました]
八進数
- C
- C++
十進数 (0
始まりの八進数もある)
- Go (
0
始まりと0o
始まりの二種類の記法が可能) - Java
- JavaScript (
0
始まりと0o
始まりの二種類の記法が可能) - Ruby (
0
始まりと0o
始まりの二種類の記法が可能)
十進数 (0o
始まりの八進数リテラルしかない)
- Haskell
- Python
- Rust
- Swift
十進数 (そもそも八進数リテラルがない)
- C#
- D
- Kotlin
- Scala
不明
- Perl (開発中のバージョンでは
0o
始まりの表記も使えるようです)
各言語の 0
の解釈の詳細
0
始まりの八進数が書ける言語についての 0
の解釈の詳細です。
C
ISO/IEC 9899:2018 6.4.4.1 Integer constants の段落 1 より:
integer-constant:
decimal-constant integer-suffixₒₚₜ
octal-constant integer-suffixₒₚₜ
hexadecimal-constant integer-suffixₒₚₜdecimal-constant:
nonzero-digit
decimal-constant digitoctal-constant:
0
octal-constant octal-digit
...
十進定数 (decimal-constant) はゼロ以外 (nonzero-digit) から始まるものと定義されているので 0
が十進数と解釈される余地がありません。
何より八進定数 (octal-constant) に燦然と輝く 0
。というわけで C では 0
は八進数。
C++
ISO/IEC 14882:2020 5.13.2 Integer literals [lex.icon] より:
integer-literal :
binary-literal integer-suffixₒₚₜ
octal-literal integer-suffixₒₚₜ
decimal-literal integer-suffixₒₚₜ
hexadecimal-literal integer-suffixₒₚₜbinary-literal :
0b
binary-digit
0B
binary-digit
binary-literal’
ₒₚₜ binary-digitoctal-literal :
0
octal-literal’
ₒₚₜ octal-digitdecimal-literal :
nonzero-digit
decimal-literal’
ₒₚₜ digit
...
C と比べると constant という言い回しが literal になっていたり二進数表記や桁区切りもできるようになっていたりとやや違いはありますが 0
に注目してみると C と同じ。
十進数は 0
から始まることができず八進数に明示的に 0
があります。
Go
The Go Programming Language Specification の Integer literals より:
A single 0 is considered a decimal zero.
と、 0
は十進数と明記されています。形式的定義では
int_lit = decimal_lit | binary_lit | octal_lit | hex_lit . decimal_lit = "0" | ( "1" … "9" ) [ [ "_" ] decimal_digits ] . binary_lit = "0" ( "b" | "B" ) [ "_" ] binary_digits . octal_lit = "0" [ "o" | "O" ] [ "_" ] octal_digits . hex_lit = "0" ( "x" | "X" ) [ "_" ] hex_digits .
となっています。十進数リテラル (decimal_lit) に 0
が明示的に含まれ、八進数リテラル (octal_lit) には 0
の後に一桁以上必要です。
Java
The Java® Language Specification Java SE 15 Edition の 3.10.1. Integer Literals より:
DecimalNumeral:
0
NonZeroDigit [Digits]
NonZeroDigit Underscores Digits
...
と、十進数 (DecimalNumeral) に明示的に 0
が入っているので 0
は十進数です。
なお八進数の定義は
OctalNumeral:
0
OctalDigits
0
Underscores OctalDigits
...
と、 0
の後に一桁以上必要な定義になっています。
JavaScript
ECMAScript® 2020 Language Specification の 11.8.3 Numeric Literals より:
DecimalIntegerLiteral::
0
NonZeroDigit DecimalDigitsₒₚₜ
なので Java と同様に 0
は十進数。
JavaScript の八進数は 0
始まりと 0o
始まりの二種類がありますが、 0
始まりの方の定義があるのは B.1.1 Numeric Literals。 strict mode では使えない記法。
LegacyOctalIntegerLiteral::
0
OctalDigit
LegacyOctalIntegerLiteral OctalDigit
ここも Java と同様、 0
の後に一桁以上必要な定義。
Ruby
Ruby-Doc.org では見付けられなかったため、現行の Ruby より古いですが ISO/IEC 30170:2012 8.7.6.2 Numeric Literals より。0
の扱いなんてそうそう変わりませんよね?
decimal-integer-literal ::
unprefixed-decimal-integer-literal
| prefixed-decimal-integer-literalunprefixed-decimal-integer-literal ::
0
| decimal-digit-except-zero (_
? decimal-digit )∗prefixed-decimal-integer-literal ::
0
(d
|D
) digit-decimal-part
...
octal-integer-literal ::
0
(_
|o
|O
)? octal-digit (_
? octal-digit )∗
0d
始まりの十進数というのもあるんですね。
それはさておき、 Java 等と同様に十進数の定義 (プレフィックスなし十進整数リテラル -- unprefixed-decimal-integer-literal) に明示的に 0
が入っており、八進数は先頭の 0
の他に一桁以上必要な定義になっています。
(以下 Ruby を不明と分類していた時の内容)
Ruby Syntax の Numeric literals の例しか見付けることができませんでした。
123
integer
-123
integer(signed)
1_234
integer(underscore within decimal numbers ignored)
123.45
floating point number
1.2e-3
floating point number
0xffff
hexadecimal integer
0b01011
binary integer
0377
octal integer
?a
ASCII code for character `a'(97)
...
この記述からは 0
がどちらなのか不明。これまた気にしていない気もします。
Perl
perlnumber の SYNOPSIS の記述程度しか見付けることができませんでした。
$n = 1234; # decimal integer $n = 0b1110011; # binary integer $n = 01234; # octal integer $n = 0x1234; # hexadecimal integer $n = 12.34e-56; # exponential notation $n = "-12.34e56"; # number specified as a string $n = "1234"; # number specified as a string
これだけでは 0
が十進数なのか八進数なのか不明。そもそも 0
が十進数なのか八進数なのかという些細なことは気にしていないのかもしれません。
おわりに
今回調べた範囲で 0
が八進数として解釈されるのは C と C++ のみで、他はすべて十進数扱いでした。C と C++ は何故異端っぷりを発揮しているのか……