アカウント名:
パスワード:
本質的に問題を生んでいるものだけではなく、たんに書いた人が使い慣れている他の言語と違う挙動をするだけ、というものが結構混ざっているような。
私にわかる分だけでも。
>Pythonでインデントレベルがブロックを示すこと
Python全否定されているんだが。CoffeeScriptはいいのか?
>Cの配列インデックスがポインターの算術演算のような動作をすること
他にどうやって配列の中身を表せと。1[a]と書けるとかの話をしている?
>Rubyで「0」がTRUEと評価されること
「0」がfalse出なければいけない理由がC出そうだという以外思いつかないのだが、何かあるのだろうが。
>JavaScriptで勝手に挿入されるセミコロン
Rubyでもそれはなかったっけ?
Cの配列インデックスってsyntax sugarと思っていなくて、本当に配列というものが存在しているかのように誤解しているんじゃなかろうか。関数の仮引数を配列形の書き方をしている人をみるとそういう気がする。
void foo(char *a){ char b[3];}
の、bは「本当に存在する配列」と違いますか?
スタックに積まれる物は、aは、「何かのアドレス」が1個だけ。bは、「b[0]」、「b[1]」、「b[2]」に相当する3つのcharになりますよ。
翻訳後の機械語の動作としても、別物になり、
x = *a; // 「スタックポインタ+コンパイル時に決まるaのオフセット(定数)」を計算→その番地の値を読み込む→その番地の値を読み込んで、xに代入x = *b; // 「スタックポインタ+コンパイル時に決まるbのオフセット(定数)」を計算→その番地の値を読み込んで、xに代入// a[0]、b[0]と書いても同様
こんな感じです。aはポインタなので、aの値(*aが指す場所)は、動作中にいくらでも変化し得ますから、それを覚えるメモリ領域が必要で、*aの値を使う場合には、aの値をメモリから取ってくる一手間がかかります。一方、bは配列なので、bの値(*bが指す場所)は、コンパイル時に決まる定数値(実際には、スタックポインタの値+定数値)ですから、その一手間は不要です。
bがスタック上のどこにあるのかをコンパイラは把握出来るので、出力する機械語にその値を直接埋め込んでしまえますから、実行時に、「変数b」に該当するような値を覚えておく必要、メモリは不要になります。
a = b;をした場合には、その、「隠れた変数bの値」がポインタ変数aに代入されるような感じです。
# なお、上記は言語仕様ではなく、全てをスタック上に確保する、のどかなコンパイラを前提にした大ざっぱなイメージ# 生の仕様で考えると馴染みの無い概念が出てきてめんどくさそうだし、変数がレジスタに割り当てられたりもややこしいので無しで
そんなことをいったら、a だってインライン展開の具合次第でなくなることはあるでしょう。あんまり本質的な議論だとは思えません。まさに、C Languageが「未定義」という必殺技を繰り出す最大の理由でしょう。C99とかではかなり論調が変わってきたのも事実ですが・・・。
いえ、aは、a++できますが、bは、b++できません。配列とポインタの本質的な違いです。
char *a = "abc";char b[]="abc";
も本質的に違い、どちらにも異なる利点・欠点があります。
未定義動作と話が繋がるのかは想像できませんでしたので説明いただけると助かります。
私が、言ったのは、
> bがスタック上のどこにあるのかをコンパイラは把握出来るので、出力する機械語にその値を直接埋め込んでしまえますから、> 実行時に、「変数b」に該当するような値を覚えておく必要、メモリは不要になります。
という部分に対して、bが変数として保存される必要がないという部分に対してです。話が分かりにくくて済みません。
一方で、
> いえ、aは、a++できますが、bは、b++できません。配列とポインタの本質的な違いです。
と言われると、C++プログラマとしては、
char const * const a = "abc";
なんていうヒネクレタ事も言いたくなる部分ではあります。
個人的には、sizeofの挙動以外、大した差ではないと思っていますが。
char *p, a[1];a[0] = 0; /* OK */p[0] = 0; /* NG */
これで大した差がないと?
いや、まじめに「配列とポインタには本質的な違いがある」という人に、このaはポインタなのか配列なのかを伺いたい。形式的にはポインタだしsizeof(a)もポインタのサイズを返すが、性質としては配列というわけでしょう?
大した差ではないな。ケアレスミスを起こすかどうかって本質的な問題じゃないでしょ。
え、まさか配列とポインタの違いも分からないの?
それが大した差でないというなら、sizeofの挙動の違い(に起因するミス)だってケアレスミスであり本質的な問題じゃないです。
"配列"といった場合、そのデータの塊を1つとして扱いたいという意味もあります。ここで sub_func(a), sub_func(b)とした場合、sub_func側で受けとるのは「何かのアドレス」aか,b[0]のアドレスかの違いでしかなく、配列の大きさの情報も,どういった領域のメモリかも受け渡しされません。"b"という識別子だけで、b[0],b[1],b[2]に相当する3つの
JavaScriptのArrayはただのオブジェクト、連想配列と言ったところで仕方ないもんな。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
アレゲはアレゲを呼ぶ -- ある傍観者
とりとめがないな (スコア:1)
本質的に問題を生んでいるものだけではなく、
たんに書いた人が使い慣れている他の言語と違う挙動をするだけ、
というものが結構混ざっているような。
私にわかる分だけでも。
>Pythonでインデントレベルがブロックを示すこと
Python全否定されているんだが。CoffeeScriptはいいのか?
>Cの配列インデックスがポインターの算術演算のような動作をすること
他にどうやって配列の中身を表せと。
1[a]と書けるとかの話をしている?
>Rubyで「0」がTRUEと評価されること
「0」がfalse出なければいけない理由がC出そうだという以外思いつかないのだが、何かあるのだろうが。
>JavaScriptで勝手に挿入されるセミコロン
Rubyでもそれはなかったっけ?
Re: (スコア:0)
>Cの配列インデックスがポインターの算術演算のような動作をすること
他にどうやって配列の中身を表せと。
1[a]と書けるとかの話をしている?
Cの配列インデックスってsyntax sugarと思っていなくて、本当に配列というものが存在しているかのように誤解しているんじゃなかろうか。関数の仮引数を配列形の書き方をしている人をみるとそういう気がする。
Re:とりとめがないな (スコア:0)
void foo(char *a){
char b[3];
}
の、bは「本当に存在する配列」と違いますか?
スタックに積まれる物は、aは、「何かのアドレス」が1個だけ。bは、「b[0]」、「b[1]」、「b[2]」に相当する3つのcharになりますよ。
翻訳後の機械語の動作としても、別物になり、
x = *a; // 「スタックポインタ+コンパイル時に決まるaのオフセット(定数)」を計算→その番地の値を読み込む→その番地の値を読み込んで、xに代入
x = *b; // 「スタックポインタ+コンパイル時に決まるbのオフセット(定数)」を計算→その番地の値を読み込んで、xに代入
// a[0]、b[0]と書いても同様
こんな感じです。
aはポインタなので、aの値(*aが指す場所)は、動作中にいくらでも変化し得ますから、それを覚えるメモリ領域が必要で、
*aの値を使う場合には、aの値をメモリから取ってくる一手間がかかります。
一方、bは配列なので、bの値(*bが指す場所)は、コンパイル時に決まる定数値(実際には、スタックポインタの値+定数値)ですから、その一手間は不要です。
bがスタック上のどこにあるのかをコンパイラは把握出来るので、出力する機械語にその値を直接埋め込んでしまえますから、
実行時に、「変数b」に該当するような値を覚えておく必要、メモリは不要になります。
a = b;
をした場合には、その、「隠れた変数bの値」がポインタ変数aに代入されるような感じです。
# なお、上記は言語仕様ではなく、全てをスタック上に確保する、のどかなコンパイラを前提にした大ざっぱなイメージ
# 生の仕様で考えると馴染みの無い概念が出てきてめんどくさそうだし、変数がレジスタに割り当てられたりもややこしいので無しで
Re: (スコア:0)
そんなことをいったら、a だってインライン展開の具合次第でなくなることはあるでしょう。
あんまり本質的な議論だとは思えません。
まさに、C Languageが「未定義」という必殺技を繰り出す最大の理由でしょう。
C99とかではかなり論調が変わってきたのも事実ですが・・・。
Re: (スコア:0)
いえ、aは、a++できますが、bは、b++できません。配列とポインタの本質的な違いです。
char *a = "abc";
char b[]="abc";
も本質的に違い、どちらにも異なる利点・欠点があります。
未定義動作と話が繋がるのかは想像できませんでしたので説明いただけると助かります。
Re: (スコア:0)
私が、言ったのは、
> bがスタック上のどこにあるのかをコンパイラは把握出来るので、出力する機械語にその値を直接埋め込んでしまえますから、
> 実行時に、「変数b」に該当するような値を覚えておく必要、メモリは不要になります。
という部分に対して、bが変数として保存される必要がないという部分に対してです。
話が分かりにくくて済みません。
一方で、
> いえ、aは、a++できますが、bは、b++できません。配列とポインタの本質的な違いです。
と言われると、C++プログラマとしては、
char const * const a = "abc";
なんていうヒネクレタ事も言いたくなる部分ではあります。
個人的には、sizeofの挙動以外、大した差ではないと思っていますが。
Re: (スコア:0)
char *p, a[1];
a[0] = 0; /* OK */
p[0] = 0; /* NG */
これで大した差がないと?
Re: (スコア:0)
char const * const a = "abc";
なんていうヒネクレタ事も言いたくなる部分ではあります。
いや、まじめに「配列とポインタには本質的な違いがある」という人に、このaはポインタなのか配列なのかを伺いたい。
形式的にはポインタだしsizeof(a)もポインタのサイズを返すが、性質としては配列というわけでしょう?
Re: (スコア:0)
大した差ではないな。
ケアレスミスを起こすかどうかって本質的な問題じゃないでしょ。
Re: (スコア:0)
え、まさか配列とポインタの違いも分からないの?
Re: (スコア:0)
それが大した差でないというなら、
sizeofの挙動の違い(に起因するミス)だってケアレスミスであり本質的な問題じゃないです。
Re: (スコア:0)
どうして混乱できるのでしょうか。
Re: (スコア:0)
void foo(char *a){
char b[3];
}
の、bは「本当に存在する配列」と違いますか?
スタックに積まれる物は、aは、「何かのアドレス」が1個だけ。bは、「b[0]」、「b[1]」、「b[2]」に相当する3つのcharになりますよ。
"配列"といった場合、そのデータの塊を1つとして扱いたいという意味もあります。
ここで sub_func(a), sub_func(b)とした場合、sub_func側で受けとるのは「何かのアドレス」aか,b[0]のアドレスかの違いでしかなく、配列の大きさの情報も,どういった領域のメモリかも受け渡しされません。
"b"という識別子だけで、b[0],b[1],b[2]に相当する3つの
Re: (スコア:0)
JavaScriptのArrayはただのオブジェクト、連想配列と言ったところで仕方ないもんな。