アカウント名:
パスワード:
プログラミング言語Cといえば、ポインタの章が理解できずに何度も読みすぎてそのページだけ黒くなっていました。ご逝去の報に接し、謹んで哀悼の意を表します。
Cの前にマシン語をやっていたので、ポインタは理解できた(というか、ポインタが理解できない人のことが理解できない)のですが、関数へのポインタの配列を返す関数にtypedefして~とか言うと、ついていけなくなります。
それから、
int *i;
は理解できますが、
int* i;
と書く発想が理解できません。「int*」って何だよ?って。
こういう型キャストも大嫌いです。
a = (int *)b;
ここで単項演算子としての「*」の立場がなくなってしまいますから。あるいは、「int」は「*」を修飾している、つまり「*」が主で「int」が従と思えば気分がだいぶ楽になりますけどね。
はっ、もしかして「int* i;」というのは、「* i;」をちょっと修飾したようなものなのでしょうか。(だと「* i,j,k;」とかいうふうに書けちゃうことになってしまうからだめですね。)
パーサを自作すれば、なぜそうなっているのか理解できるんでしょうね。きっと、「*int」と表記することにすると、どこかで破綻するんでしょう。
考え方の1つにすぎませんが,型宣言でも数式解釈と同様に,両辺の型が釣り合っていると思えばわかりやすいかも知れません.
は
int = *i; (この式はコンパイラに通りませんが概念的なものです)
というように両辺の型が釣り合う関係になっていて,アドレス(ポインタ) i が指す先の値にアクセスする演算子 * を付けたもの (*i) は,int 型でなければなりませんよ,という意味です.コンパイラの視点で言うと,代入式を解釈するときの左右の型の一致判定と同じロジックで変数宣言が出来ることになりますし,変数への演算子の付け方が許容されうる限り,それは変数宣言でも同じように使える
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
目玉の数さえ十分あれば、どんなバグも深刻ではない -- Eric Raymond
プログラミング言語C (スコア:0)
プログラミング言語Cといえば、ポインタの章が理解できずに何度も読みすぎてそのページだけ黒くなっていました。
ご逝去の報に接し、謹んで哀悼の意を表します。
Re: (スコア:0)
Cの前にマシン語をやっていたので、ポインタは理解できた(というか、ポインタが理解できない人のことが理解できない)
のですが、関数へのポインタの配列を返す関数にtypedefして~とか言うと、ついていけなくなります。
それから、
は理解できますが、
と書く発想が理解できません。「int*」って何だよ?って。
Re: (スコア:1, 興味深い)
pint_t a, b, c;
…わかりやすいでないですか。
と、いうのは全然嘘です。
私もその書き方が気に入ってません。
int* i;
と書かなければ気が済まない人というのは、
「ポインターなのは型だろー、型は型として書かせてくれよ。」
って思ってる人たちなんです。
きっと型名にスペースを含んでいるのが許せない人達なんです。
または、* が型名に含まれていない事が我慢できない人達なんです。
そう思ってる人たちは決して、
int* i, *j, *k;
とは書かない/書けないみたいですね。
そんなに嫌なら、typedef しやがれですよ。> 各位
Re: (スコア:0)
こういう型キャストも大嫌いです。
ここで単項演算子としての「*」の立場がなくなってしまいますから。
あるいは、「int」は「*」を修飾している、つまり「*」が主で「int」が従と
思えば気分がだいぶ楽になりますけどね。
はっ、もしかして「int* i;」というのは、「* i;」をちょっと修飾したような
ものなのでしょうか。(だと「* i,j,k;」とかいうふうに書けちゃうことになって
しまうからだめですね。)
パーサを自作すれば、なぜそうなっているのか理解できるんでしょうね。
きっと、「*int」と表記することにすると、どこかで破綻するんでしょう。
Re: (スコア:2)
考え方の1つにすぎませんが,型宣言でも数式解釈と同様に,両辺の型が釣り合っていると思えばわかりやすいかも知れません.
int *i;
は
int = *i; (この式はコンパイラに通りませんが概念的なものです)
というように両辺の型が釣り合う関係になっていて,アドレス(ポインタ) i が指す先の値にアクセスする演算子 * を付けたもの (*i) は,int 型でなければなりませんよ,という意味です.コンパイラの視点で言うと,代入式を解釈するときの左右の型の一致判定と同じロジックで変数宣言が出来ることになりますし,変数への演算子の付け方が許容されうる限り,それは変数宣言でも同じように使える
Re: (スコア:0)
考え方の1つではなくて、そう定義されています。
fがcharの配列へのポインタを返す関数へのポインタの場合、使うときにはこう書くでしょ。
(Pascalだとpointer to function():pointer to array [1..10] of char)
(*(*f)())[5] = 'a';
宣言するときにはtype specifierの後にそのまま左辺をコピーして
char (*(*f)())[10];
キャストするときは、左辺から識別子を抜いて
f = ((*(*)())[5])g;
非常に分かりやすいですね。
分かりにくいのは演算子の優先度がややこしいからだね。
Re: (スコア:1)
> ...
> char (*(*f)())[10];
> f = ((*(*)())[5])g;
charが抜けてませんか?
f = (char(*(*)())[5])g;
でもって f がこの型で定義されているなら、
> (*(*f)())[5] = 'a';
は(*)が1つ多いですな。(多い分はOKなので問題ないですが)。
(*f())[5] = 'a';
でよいですよ。(理由は()演算子(関数呼出し演算子)は暗黙のうちのdereferenceをやるから。想像するに、K&Rの時代にfが関数ポインタのときに、(*f)()でなく、f()でOKとしていた仕様に合せたんでしょうね)
ただし、型宣言やキャストのときは暗黙のdereference
Best regards, でぃーすけ
Re:プログラミング言語C (スコア:0)
| struct a { char data[5]; };
中略
| f()->data[5] = 'a';
私の中でエンガチョ警報が鳴り響きました。