by
Anonymous Coward
on 2011年01月31日 17時10分
(#1896060)
言語仕様と実装の問題をいっしょにするのはどうかと思いますが。 間違ったコードはちゃんとコンパイル時及び実行時にエラーとして叩き落とす実装(たとえばFail-Safe C [aist.go.jp])を使えばいいんじゃないでしょうか。Cの言語仕様はこのような実装を禁じていません。未定義とは文字通り「何をしてもいい」ので、コンパイルエラーや実行時エラーにしてもいいのです。 「そんなもん仕事では使わん」と言うなら、Pascalだって仕事で使うことなんかありませんし。むしろ(将来Cで仕事をさせる予定の人間に)過保護な高級言語ばかり使わせていると、間違ったコードはちゃんと言語がエラーにしてくれると思い込んでしまいませんか?
CはCでも・・・ (スコア:5, おもしろおかしい)
世の中はCでできている。WindowsだってLinuxだってアメンボだって、みんなみんなCでできている。
プログラミング言語だってCでできている。PythonだってRubyだってオケラだって、みんなCでできている友達なんだ。
アメンボとオケラのCは炭素では?
Re:CはCでも・・・ (スコア:0)
Cの難易度が誇張されているように思うのだが。
Javaより難しい?
Re:CはCでも・・・ (スコア:1, すばらしい洞察)
世の中にはポインタの加算でなにが起きるか理解できてないのが結構いますから。
Re: (スコア:0)
Re:CはCでも・・・ (スコア:2, 興味深い)
わからんでもないけど、この文脈だと「ポインタの加算」は「ポインタ値への数値加算」でいいと思うんだが。
...人間には優しくないからこそ、分かりやすいほうに倒して会話しないとドッチボールになっちゃうし
M-FalconSky (暑いか寒い)
Re: (スコア:0)
Re: (スコア:0, 荒らし)
>そしてコメントした側には「思慮の足りない表現かもしれない」という思慮が足りていない。
そう、つまり、元が思慮が足りてない以上、それにレベルをあわせた回答があっても、元の責任ということね。
>ちなみに、あなたは「思慮の足りない表現かもしれない」という思慮が足りていない可能性について思慮が足りていない。
つまり、思慮が足りないあなたのことですね。
Re: (スコア:0)
Re:CはCでも・・・ (スコア:4, 興味深い)
> ポインタ同士の演算はコンパイル通らないから
ポインタ同士の"引き算"ならコンパイル通りますよ。
Re:CはCでも・・・ (スコア:1)
同じ型なら引き算は通る(比較も通るけど)。結果は「(ポインタ-ポインタ)/型サイズ」だったような。
Re:CはCでも・・・ (スコア:1)
と書きたかったのかな?その理解で問題ないですが、C(++)は一応「高級」言語なのでアセンブリレベルで理解しなくとも、その型の変数が間に何個入るかという理解もできます。
template<typename T>
....
T array[100];
T *p = array +10, *q = &array[55];
int x = q-p;
これで x には 45が入るという寸法です。
Best regards, でぃーすけ
Re: (スコア:0)
「実装でどうなってるかわからないな」と目星をつけてもらいたいところ。
「そらわからんな」がこういうわからなさを指しているとは思えないけど。
Re: (スコア:0)
ポインタの型って指している先が何であるかを示すヒントでしかなく、実態はしょせん(通常)4バイトの整数型なんだから型に寄らず演算はできると思った。。。
Re: (スコア:0)
Re:CはCでも・・・ (スコア:1)
いや、Cのポインタにおいて、型のサイズは重要ですよ。ヒントどころじゃない。
たとえば、int *ptr1,*ptr2、sizeof(int)==4なら、
ptr2=ptr1+1;
としたときに、アドレスで見るとptr2はptr1に4バイト足した位置を指すようになるわけです。
ここから、逆に、ptr2-ptr1==1 になるようになっていて、演算の対称性が保証されている。
つまり、ポインタ同士の引き算は「(ポインタ-ポインタ)/型サイズ」 [srad.jp]となる。
このようなサイズ情報込みで考えると、「ポインタと整数の加減算」および「ポインタ同士の減算」は定義できても、「ポインタ同士の加算」は定義できません。
(ポインタと整数の加算は交換則が成り立つようになっていて「ポインタ+整数」「整数+ポインタ」どちらも結果はポインタ。
「ポインタ+ポインタ」を、「ポインタと整数の加算」と見なすには、どちらを整数と見なすかという情報が無いし、
ポインタのサイズによっては、どちらを整数と見なすかで結果が変わります。)
#Cの配列アクセス「array[index]」は、「*(array+index)」のシンタックスシュガーなので、「整数+ポインタ」という順番での加算計算できるってことは、「index[array]」って書いても問題ないんですよね。
#「data = 5[ptr]; 」みたいなコードを書くと、「data=*(5+ptr);」と解釈され正しく動作するけど混乱の元。
Re: (スコア:0)
C言語のポインタごときで躓く人は適性がないから、そこで脱落したほうが幸せなので、わざと放置するが、
いまでは、ポインタはハンドルとしての使い方だけで十分なので、そう教えると簡単だよ。
ポインタに関する、使いもしないテクニックなんか習得しても無駄だし、そこで引っかかって立ち止まるのはアホらしい。
いまどきのコンパイラなら、配列の添え字を使っても速度に大差ないし。
Re: (スコア:0)
ポインタa とポインタb の足し算a+bは
bを整数と見立ててaの型でb個分先を指すとコンパイラが解釈するか
型に関するコンパイラエラーがでるかどっちかだと想像白。
たしかに、その想像ができない程度じゃCを使うとドツボにはまりそうだな。
Re: (スコア:0)
理解できてないじゃん……自明でない疑問に不確定な答え返して何がしたいんだか。
Re: (スコア:0)
Re: (スコア:0)
言語の曖昧性が多く残っていて、難易度は高いと思いますけど。
#最近はi=i++の動作仕様って決定された?私自身が読んだ仕様書は、ANSI C89でおしまい。
Re:CはCでも・・・ (スコア:1, 興味深い)
C++0xでも相変わらず未定義です。定義しても並列化などがやりにくくなるだけなので、そんな軟弱な規定はほかの遅い言語に任せてください。
Re: (スコア:0)
私もCは簡単だと思いますが、それは、アセンブラを知っていたからだと思っています。
Re: (スコア:0)
Re: (スコア:0)
Re: (スコア:0)
私もCは簡単だと思いますが、それは、自称イケメンだからだと思っていますw
Re:CはCでも・・・ (スコア:1)
「自称イケメン」と自称するってことは、「イケメン」とは自称しないってことか?
the.ACount
Re: (スコア:0)
Cの難易度が20でC++が30ってのが?
CとC++の難易度の差は、「プログラミング言語C」と「プログラミング言語C++」の
厚さの差にほぼ比例すると思うぞ。
Re: (スコア:0)
>Cの難易度が20でC++が30ってのが?
C++の習得には前提知識としてCの習得が必須ですが、その分が「30」には含まれてないんですよ。
なので、何も知らない人がC++を習得する難易度は20+30=50になります。
Re: (スコア:0)
#でも、実行速度やメモリ使用量の関係で、embedded C++ぐらいにしかC++を使っていません。だったらCでいいじゃん、と思われるかもしれませんが、私も時々、そう思います。Cにする積極的な理由がないだけです。
Re:CはCでも・・・ (スコア:1, すばらしい洞察)
何も知らない人にC++の言語仕様をきっちり教えこんでも、ちゃんと例外を考慮したコードが書けるとは思えません。
Re: (スコア:0)
話はずれますが…例外の思想に関しては他の(例外機構の無い)プログラム一般にとっても有用な場合があるので出来れば取り扱いを教えるべきだと思います。
特に頻出するのはファイルの書き込みですね。通常何らかの理由で書き込みに失敗するとデータファイルは壊れますが、例外の考え方に沿った扱いをすれば(オーバーヘッドと引き換えに)データ破壊の危険性をより低くできます。
Re: (スコア:0)
Re:CはCでも・・・ (スコア:1, 参考になる)
しかしC++の場合、言語仕様にきっちり準拠したコードを書くことが、言語仕様を学ぶだけでは、困難なのです。
コンパイラは何も文句を言わないし、ランダムテストする限りは正常に動いているように見えるし、出荷後にも何のトラブルも報告されてこないが、しかし、本当によくC++を理解している人にコードレビューしてもらうと、C++の言語仕様に準拠していないという指摘を受ける、それがC++の恐ろしいところなのです。
有名なオープンソースのプロジェクトのコーディング規約に、例外なし、という記述を見かけるのは、そういうことだと思っています。
Re: (スコア:0)
間違ったコードが間違ったまま動くから、独習するのは難しいと思います。
Cだけ学ぶより、CPUやコンパイラをセットで学んだほうが楽だと思えるぐらい。
先日某所で char number[sizeof(int)]; というブットビコードを見かけました。
整数を一旦文字列にしようと思ったらしいですが、スタック壊しながら動いちゃいますから、初学者は何が悪いか気がつきませんよね。
Re:CはCでも・・・ (スコア:3, 参考になる)
言語仕様と実装の問題をいっしょにするのはどうかと思いますが。
間違ったコードはちゃんとコンパイル時及び実行時にエラーとして叩き落とす実装(たとえばFail-Safe C [aist.go.jp])を使えばいいんじゃないでしょうか。Cの言語仕様はこのような実装を禁じていません。未定義とは文字通り「何をしてもいい」ので、コンパイルエラーや実行時エラーにしてもいいのです。
「そんなもん仕事では使わん」と言うなら、Pascalだって仕事で使うことなんかありませんし。むしろ(将来Cで仕事をさせる予定の人間に)過保護な高級言語ばかり使わせていると、間違ったコードはちゃんと言語がエラーにしてくれると思い込んでしまいませんか?
Re: (スコア:0)
残念ながら、Cの仕様では、コンパイル時にすべての未定義コードを簡単には蹴ることができないんですよ。例えば、
a[i] = a[j]++;
は、実行時に、i==jだったら未定義になりますが、コンパイル時に、それを検出するのは容易ではありません。
Re:CはCでも・・・ (スコア:2)
#釣り?
なんら、変な所ないのですが・・。
>整数を一旦文字列にしようと思ったらしいですが、スタック壊しながら動いちゃいますから、初学者は何が悪いか気がつきませんよね
盛大な釣り?
閑話休題
Re: (スコア:0)
このコメント自体が盛大な釣りですか?
とりあえずあなたが初学者さんと同レベルであることはよく分かりましたので、願わくは一生Cのプロジェクトで関わり合いにならないことを祈っておきます。
Re:CはCでも・・・ (スコア:4, おもしろおかしい)
> 願わくは一生Cのプロジェクトで関わり合いにならないことを祈っておきます。
賛同者は多いとおもいますが、経験的には、その類の願いが叶うことは決してありません。(泣
Re:CはCでも・・・ (スコア:2, すばらしい洞察)
c言語の欠点が、まさにこの問答で現れていると思いますよ。「初学者」と「Cのプロジェクト」参加者との、このギャップを埋める努力を誰がしているのか、と。もしかしてその努力って、初学者の自助努力に大きく頼っていませんか。
初学者が「Cのプロジェクト」参加者レベルまで達するのに必要な学習はどのようなもので、それは独学で可能か?あるいは、間違って覚えたことを修正するのにはどうすればよいか?
客にカネを払わせるに値するプロジェクトの推進には初学者は無用でしょうが、「Cのプロジェクト」参加者レベルの人材が天から降ってくるわけもなく、何らかの形での教育は必要不可欠なわけですよ。まして、フリーソフト(たとえばlhaplusとか・・・ただしこの設例に他意はありません)などは一人でやっているわけで、その人が仮に間違った知識でコーディングしていたら?間違っているが偶然にも動いてしまう場合は?等等
c言語の使い手の雰囲気って、初学者を排除する文化が蔓延しているように見えます。「Cのプロジェクト」参加者レベルとしてはそれでいいのでしょうが、初学者を邪魔者扱いでは、その初学者がいずれ書くであろうプログラムの質はいつまでたっても上がらないでしょう。
意味不明 (スコア:0)
> それは独学で可能か?あるいは、間違って覚えたことを修正するのにはどうすればよいか?
それは初学者当人やその上司、PMの問題であって、「言語」の問題とは一切関係無いよ。
或いは貴方がこれまで参加してきた「C言語によるプロジェクト」の巡りあわせが
極めて不運だったのでしょう。
Re: (スコア:0)
知らないなら素直に「どこがおかしいのかわからないから教えてください」と言えばいいものを「釣り?」とかほざくのが言語の問題? 言いがかりにもほどがある。
これが不遜メソッド [hatena.ne.jp]って奴ですか?
Re: (スコア:0)
ごめんなさい、別コメでも補足しましたが、その後に
sprintf(number, "%d", some_small_integer);
ってのが来るのです。整数が3桁までなら動いているので、その時点で何がおかしいかを知る手段はない。ですが、4桁目まで使ってしまうとスタック壊しますよね。メモリの置き方によってはこれでも動いてしまう場合があるのですが、こことは直接無関係な変更をした瞬間に動かなくなって、どこが原因だかわからなくなってハマっている、なんてこともしばしば。
実際人のこと言えず、配列を踏み越えちゃったり解放したメモリへの参照が残ってたり、なんてケースではバグの発生条件が不確定だったりバグを顕在化した変更とバグの原因が遠かったりで、なかなか大変な目に遭うことも。ええ、僕自身が「Cのプロジェクトで一緒になりたくない」存在かもしれませんね…orz
Re:CはCでも・・・ (スコア:2)
> sprintf(number, "%d", some_small_integer);
うがぁ;;
笑えないですね;;。
そこで、「%*.」「%.*」「%*.*」とかを教えてあげましょう。
彼も一つのスキルを手に入れられます。
閑話休題
Re: (スコア:0)
> char number[sizeof(int)];
すみません、何が悪いのか分かりません。
int型の変数とセットでunionとして使えば使い道があるような気がしました。
Re: (スコア:0)
元コメの言う通り数値⇒文字列変換なら桁数が全然足りてないのでは。
unionはバイトコード変換なら使うでしょうけど、文字列には変換できませんよね?
Re: (スコア:0)
> 元コメの言う通り数値⇒文字列変換なら桁数が全然足りてないのでは。
> unionはバイトコード変換なら使うでしょうけど、文字列には変換できませんよね?
「文字列変換」が意味するところは、まさにそういう意味だと思ってました。
0x41424344 -> "ABCD" または "DCBA" (エンディアンによる)(32ビットintの場合)
といったことを、やりたいのだと思ってました。
sprintfみたいなことがやりたいのなら、これではだめなことは明白ですね。
Re: (スコア:0)
元の話ですが、fizzbuzzの話で、なぜかsprintfを使いたかったようです。
わかりづらい書き方してごめんなさい
Re: (スコア:0)
「バイトコード変換した結果を文字列として扱う」だとしても、今度は「終端文字分を確保していない」という罠が待ってますよん。
#まぁこっちではなかったようですが。
Re: (スコア:0)
Cのポインタ周りは鶴亀算を覚えるような時のような難しさが
ある一方で、Javaはもっと概念的・感覚的な難しさって言うか。
CはB型向きで、JavaはO型向きって感じだと私は思ってる。
Re: (スコア:0)
JavaはGCがあるため、インスタンスとオブジェクトの違いも分からない人間にとっては簡単です。
元記事でCは難しいけどC#は簡単とか書いてるあたり、たぶんその手のインスタンスが何たるか把握しきれてない人間なんでしょう。きっとポインタでも躓いているはず。
致命的なレベルで理解不足を起こしていても動いてしまうので、"簡単に見える"だけの錯覚です。
致命的じゃないレベルまで理解しようとするなら、ポインタの言語仕様よりオブジェクト指向の言語仕様のほうが確実に難しい。