Linux Kernel Mailing Listからの論争の的となっているアイデアに関する最近の手紙の翻訳に注目してください。これはLinus Torvaldsの伝統的な反応を引き起こしました。 必要な説明は 、投稿の最後に記載されています。手紙
送信者:マーティンワッカー
日付: 2018年3月20日火曜日22:13:35 +0000
トピック:マクロでの整数定数式の検出
こんにちはLinus
私はアイデアを得ました:
整数定数式 ( 
ICE )自体を返す整数定数式のテスト。これは
__builtin_choose_exprに渡すのに適しているはずで、次のようになります。
 #define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1))) 
ちなみに、この式では、 
x自体は
gccで評価されませんが、これは標準では保証されていません(古いバージョンの
gccではこの事実を確認しませんでした)。
リーナス・トーバルズ回答
送信者: Linus Torvalds <>
日付: 2018年3月20 日(火)16:08:30 -0700
件名: Re:マクロでの整数定数式の検出
2018年3月20日火曜日、午後3時13分、マーティンウェイカー
<Martin.Uecker@med.uni-goettingen.de>はこう書いています:
私はアイデアを得ました:
いいえ、これは「アイデア」ではありません。
これは天才の仕事か、頭が完全に病気のどちらかです。
まだ完全には定かではないので、正確に言うことはできません。 
整数定数式自体を返す整数定数式のテスト。これは__builtin_choose_exprに渡すのに適しているはずで、次のようになります。
 #define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1))) 
OK、ここで
xが
ICEときに
(void *)((x)*0l))が
NULLになることが
(void *)((x)*0l)) NULL 。 いいね 定数を使用すると:
 sizeof( 1 ? NULL : (int *) 1) 
そして、ここでの規則は次のとおりです。ポインターを持つ三項演算子の辺の1つが
NULL場合、最終結果は異なる型
(int *)ます。
そう、はい、上の式は
sizeof(int)返します。
また、ICEで
ない場合、最初のポインターは(void *)型のままですが、 
NULLはありません。
そして、はい、それぞれが
NULLでない2つのポインターを持つ三項演算子の型キャスト規則は異なり
NULL 。したがって、 
"void *"返します。
したがって、最終結果は
(sizeof(*(void *)(x))になります。これは、 
gccでは通常
intとは
異なります。
そこで、ここで2つの問題を観察しています。
"sizeof(*(void *)1)"必ずしも厳密に定義されて"sizeof(*(void *)1)"わけで"sizeof(*(void *)1)"ません。 gccの場合、これは1です。これにより、警告が発生する可能性があります。- この表現をキャッチするすべての人の脳を破壊します。
 
ただし、これらの問題は両方ともそれほど重要ではない可能性があり、これはすべて標準である可能性があります。
ちなみに、この式では、 x自体はgccでは評価されませんが、これは標準では保証されていません(古いバージョンのgccではこれを確認しませんでした)。
ああ、私にとっては、 
sizeof()演算子が引数の値を計算するのではなく、その型のみを計算する
ことを保証するのは標準です。
私はあなたの本当に驚くべき、嫌な「ハック」に喜んでいます。 それは本当の芸術作品です。
さまざまな理由でこれが機能しないか、警告を発生させると確信していますが、
まだ
完璧です。
ライナス
このコードで何が起こっているのかを理解してみましょう。
 #define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1))) 
マクロ
ICE_P(x)を定義します。 
Pは、命名規則によれば、 
簡単な述語です。 ICEは整数定数式を表します。 
xが整数定数式の場合は
trueを返し、それ以外の場合は
falseを返し
true 。
この式は、比較の右側が
sizeof(int)と等しい場合に
trueなり
true 。 デプロイしてみましょう。
 sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1)) 
この式は、3項式が指す型のサイズを返します。 より深く掘ります。
 1 ? ((void*)((x) * 0l)) : (int*)1 
もちろん、1は常に
trueなので、左側は常に戻り
true 。 Linusが説明するように、 
xがICEの場合、左側は
NULLになり
NULL 。 次の2つのオプションがあります。
xがICEの場合: 
1 ? ((void*)(NULL)) : (int*)1 1 ? ((void*)(NULL)) : (int*)1xがICEでない場合: 
1 ? ((void*)(NOT-NULL)) : (int*)1 1 ? ((void*)(NOT-NULL)) : (int*)1唯一の違いは、左側の
void*が
NULLかどうかです。
NULL (xはICE)の場合、式は
int*型を返します
int*NULLでない場合(xはICEではありません)、式は
void*返し
void*基本的に、三項式は
NULL void *を
int *に変換でき
NULL void *が、 
void *が
NULLでない場合、代わりに
int * void *に
int * void * 。 これで元の式に戻ることができ、次の結果が得られます。
xがICEの場合: 
sizeof(int) == sizeof(*(int *))xがICEでない場合: 
sizeof(int) == sizeof(*(void *))void *の逆参照は有効な操作で
はありませんが、 
sizeofは魔法であり、コンパイル時に完全に計算されます。 
gccでは、コード
sizeof(*(void *)) 1になります。
以下に、このマクロをテストするためのサンプルコード
icep.cます。
  #include <stdio.h> #include <stdlib.h> #define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1))) #define CHECK(x) printf("ICE_P(%s): %d\n", #x, ICE_P(x)) int main() { CHECK(1); CHECK('c'); CHECK(rand()); return 0; } 
追加説明
ここでのキー式は、ちょうど
x * 0です。 
xが整数定数の場合、コンパイラーは計算を実行でき、ゼロの整数はゼロです。 
xが整数定数でない場合、コンパイラはこの計算を実行できず、ゼロであるかどうかはわかりません。 この結果は
voidポインターにキャストされ
ます 。 これは、 
NULLかどうかを調べる方法です(ゼロへの
voidポインターは
NULLの定義であるため)。
この式を理解するためのもう1つの鍵は、タイプ
a ? b : c a ? b : c bと
cは異なる型を持つことができることは明らかであり、この場合、コンパイラはこれらの式の「共通」型を把握する必要があります。 ここで、 
cは
intへの明示的なポインターです。 ただし、 
NULL他のタイプのポインター
NULL互換性があります。 したがって、 
bが
NULL場合、ジェネリック型は両方の式を記述するため、 
int*です。 ただし、 
b NULLかどうかが静的に不明な場合、 
void*および
int* void*唯一の型は
void*です。
これにより、 
xが整数定数式でない場合は
sizeof(*(void*)) 、 
xが整数定数式である場合は
sizeof(*(int*))します。