C言語の整数定数の型について、規格の記述をまとめました。C言語について記していますが、C++言語でも同じです。
整数定数は型をもちます
整数の変数は型を持ちます。それと同じように整数の定数も型を持ちます。
用語を定義しておきます。
- 整数定数:以下のどれか。後で示す整数接尾語を付けてもよい。
- 10進定数:0以外で始まる。0から9が続く。基数は10
- 8進定数:0で始まる。0から7が続く。基数は8
- 16進定数:0xまたは0Xで始まる。0-9、a-f、A-Fが続く。基数は16
補足として、0は文法上は8進定数になります。16進定数は、英字小文字でも大文字でも構いません。
- 整数接尾語:整数定数の後ろにつける。以下のどれか。
- U接尾語:uまたはU
- L接尾語:lまたはL
- LL接尾語:llまたはLL ※C90には存在しない。
C90では、U接尾語を符号無し接尾語と、L接尾語を長語接尾語と呼んでいました。C99からLL(long long)が導入されたため、用語を変更したようです。
整数定数の型
表で示します。定数整数は、次の並びのうちでその値を表現できる最初の型となります。
定数 | C90の型 | C99以降の型 |
10進定数かつ 整数接尾語なし | int long int unsigned long int | int long int long long int |
(8進定数または 16進定数)かつ 整数接尾語なし | int unsigned int long int unsigned long int | int unsigned int long int unsigned long int long long int unsigned long long int |
U接尾語付き | unsigned int unsigned long int | unsigned int unsigned long int unsigned long long int |
10進定数かつ L接尾語付き | long int unsigned long int | long int long long int |
(8進定数または 16進定数)かつ L接尾語付き | long int unsigned long int | long int unsigned long int long long int unsigned long long int |
U接尾語付き かつ L接尾語付き | unsigned long int | unsigned long int unsigned long long int |
10進定数かつ LL接尾語付き | 存在しない | long long int |
(8進定数または 16進定数)かつ LL接尾語付き | 存在しない | long long int unsigned long long int |
U接尾語付き かつ LL接尾語付き | 存在しない | unsigned long long int |
参考までに規格の記述してある場所を記しておきます。
- C90:JIS X 3010:1993 6.1.2.3
- C99以降: JIS X 3010:2003 6.4.4.1
※ISOのC11、C17も調べましたが仕様は同じでした。
実際の例
ABC269C問題(解説)は、bit全探索を行う典型的な問題となります。以下のコードで、AC(正解)となります。
20、23、24行目を単に「1」と書くと、上述の整数定数の型の規則により int となります。AtCoderの環境では、int は32ビットです。問題の制約($0 \leqq N < 2^{60}$)から、64ビット整数が必要となります。
20行目は、size() は unsigned を戻すため、ULL を付けないと動作しません。
23、24行目は、シフト演算の右辺を unsinged long long にしているため、型のバランシングにより、1と書いても、演算をする前に unsinged long long 型に暗黙の型変換が行われるため動作しますが、1ULL と書いたほうが意図が伝わりやすいでしょう。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long int ull;
int main()
{
ull n;
cin >> n;
vector<ull> p;
vector<ull> result;
for (ull i = 0; i < 64; ++i) {
if ((n & (1ULL << i)) != 0) {
p.push_back(i);
}
}
for (ull bit = 0; bit < (1ULL << p.size()); ++bit) {
ull n = 0;
for (ull i = 0; i < p.size(); ++i) {
if ((bit & (1ULL << i)) != 0) {
n += (1ULL << p[i]);
}
}
result.push_back(n);
}
for (int i = 0; i < result.size(); ++i) {
cout << result[i] << endl;
}
return 0;
}
最後に
整数定数の型について、自分の頭を整理するために記事にしました。
C言語を使いこなしていきましょう!