ネットで、
int a[3];
int j=1;
a[j] --> *(&a[0] + j) --> *(a + j) --> *(j + a) --> j[a]
と云うのを見つけた。
要点は四則演算の+演算子の前後は差し替えOKなので、
*(a + j) === *(j + a)
であるとこで、C++ではポインタとintは同値扱いだから通る。(んだろうなぁ
実際、その通りだと思うけどね。
CPUのクロックが1MHzでメモリも数キロバイトな20世紀の頃ならともかく、
CPUのクロックが1GHz越えでメモリも数Gバイトな21世紀の昨今の視点で観ると
C++コンパイラが int j と宣言してるのにjの配列を認めない位のチェックはやっても良さげなので意外だった。
それでも、コンパイラがOKしてしまえば、C++のソースがアセンブラを通して機械語に変換されてしまえば・・・
多分、こんなアセンブラになって
データ・セグメント・レジスタ ds
データ・インデックス・レジスタ idx
データ・オフセット・レジスタ ofs
a[j] は、 Add ds, idx, ofs
j[a] は、 Add idx, ds, ofs は多分CPUの機械語には無いので、Add ds, idx, ofsに置き換えられるハズ
となり、どっちも同じに機械語に変換されるはずなので、(ま、いいか的にコンパイルも通すのかな?
a[j] = 4 とすれば・・・
同じ意味の機械語に翻訳されるj[a]も4になるのは当たり前。
不思議でも何でもない。
と思った。
しかし、WebAssemblyしか知らないと、Webで使う言語ではj[a]はエラってしまうと思うので
ソンナコードは通らない!
だから、C++が変!
と云うことになるのだろう。
そこにつっこみを入れるなら、
int a[3];
a[1000]=1; // オーバーランしてるので、スタックのどこかが破壊される。
だって、コンパイルは通るだろうし、
関数のポインタだって何か変だなぁと思うトコはある。
そんなことよりも、ビット長が異なるCPUでも、異なるOSでも、同じソースが使え移植性の高いコンパイラというトコがずっと優先度が高い。
もしC++がなかったら、異なるOSやCPUで同じ言語を提供するには、全く別々のコードを書かなければいけないと思うが、今はWebAssemblyを使えば問題なし かもしれない。
でもそんなWebAssemblyはC++無しではリリースできない様な気がするので、
一般のプログラマはC++には手を出さない方がいい。
と思う。
そもそも、intとポインタが同一視されている理由は、OSやドライバ内部では、他人のモジュールが引き渡してくるポインタって実際にはアクセス不能だったり(CPUからGPUのメモリが見えるとは限らない等)するからintも同然なので、仕方が無いんだよなぁ。
CPU:ポインタって言ってますけど、それって貴方(GPU)の感想(アドレス)ですよね?
的な・・・(笑
手元のWindows上のArdunoの開発環境はx86-64系CPUで見知らぬCPUのコードをクロスコンパイルしてるのでArduno内部のアドレスもintもx86-64系CPUから見れば、どっちも只のint型データでしかない。
移植先のターゲットっていつも貧弱で自前ビルドなんて無理、高価な機械でクロスコンパイラするのが当たり前なC言語ができた頃の常識が今も残ってる。
そんな感じがした。