C言語なら俺に聞け 147

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん
垢版 |
2018/08/16(木) 23:36:02.22ID:fOCSKLtw
C言語の話題のみ取り扱います C++の話題はC++スレへ
質問には最低限の情報(ソース/コンパイラ/OS)を付ける
数行で収まらないソースは以下を適当に使ってURLを晒す
https://paiza.io/
https://ideone.com/
http://codepad.org/

C11
http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1570.pdf

C99
http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
http://kikakurui.com/x3/X3010-2003-01.html

C FAQ 日本語訳
http://www.kouno.jp/home/c_faq/

JPCERT C コーディングスタンダード
https://www.jpcert.or.jp/sc-rules/


C言語なら俺に聞け 146
https://mevius.5ch.net/test/read.cgi/tech/1525031257/
2018/08/27(月) 13:22:18.19ID:vY3QDx2y
何人たりともforより先に関数のブロックを憶えるのにね
関数のブロックだけが何か特別なものと思い込んでるケースが多い
2018/08/27(月) 13:25:30.84ID:Q5lEKL35
goto 便利だけどなぁ。
break するがためのフラグ作って何ブロックも break するとか goto を避けるがためのいびつな if を連続させるとかよりよほど可読性が高い。
もちろん意味を的確に表したフラグやifの構造にできるに越したことはないけどさ。
2018/08/27(月) 13:28:07.17ID:aXwyVMA/
>>523
あえて固執して解決方法を編み出しておくと
ひょんなときに役立つことがあるしな
準備なんてのは9割無駄で当たり前だよね
2018/08/27(月) 13:31:18.13ID:vY3QDx2y
ジャクソン法やワーニエ法みたいに
データ構造とプログラム構造を一致させる構造化プログラミング()では
データが損傷していた場合にはプログラム構造を一致させることができない
よって構造化定理を諦めたアプローチをせざるを得ない
こういうのがgotoやlongjmpの出番
2018/08/27(月) 13:32:12.14ID:vY3QDx2y
>>529
その説明じゃ変態行為に固執する理由が説明できてないだろ
ええ加減にせんか、この変態!
532デフォルトの名無しさん
垢版 |
2018/08/27(月) 13:35:23.06ID:ywsjsNTA
ま、Cの場合は適切にgoto使った方が良いだろうな。後から作られた言語では break でラベル指定できるだの例外処理できるだのしてるから使わなくて済むようになってるわけで、それのないCはそれの代わりにgoto利用しちゃった方が分かりやすく書ける。
2018/08/27(月) 13:41:42.47ID:vY3QDx2y
いやCのgotoは制限がキツすぎて
いざという時には役立たず
だからlongjmpがある
2018/08/27(月) 14:22:47.97ID:Q5lEKL35
そんな制限キツかったっけ?
longjump の方がキツいでしょ
2018/08/27(月) 14:23:38.81ID:vY3QDx2y
何がキツいって関数から出らんない
2018/08/27(月) 14:34:05.72ID:J1p6Vf0T
setjump/longjumpは簡易タスクディスパッチャーをC言語だけで実現するためだけにあるのかと思ってたよ。
それ以外の用途はあんまり思い浮かばないなぁ。
2018/08/27(月) 14:40:44.92ID:TsaU1TVW
自分で対処不能なエラーが起きたときに、初期化してやり直す時に使ったな
だもんで通常の処理の流れで使うものだとは思わなかった
2018/08/27(月) 16:09:02.07ID:vY3QDx2y
ディスパッチャとしてはダメダメじゃん
jmp_buf jb;

void sig(int n)
{
longjmp(jb, 1);
}

int main(void)
{
signal(SIGINT, sig);
if (setjmp(jb) == 0) for (;;) ;
else puts("ok");
return 0;
}
俺んとこではokが出ない
おまいらんとこではどんな結果になる?
2018/08/27(月) 16:16:45.47ID:J1p6Vf0T
確かsignalとlongjmpは相性悪かったような?
よく覚えてないけど。
540デフォルトの名無しさん
垢版 |
2018/08/27(月) 16:27:43.33ID:VuJs8kRo
>>538
こちらは Linux (CentOS7)だが、出たよ。
541デフォルトの名無しさん
垢版 |
2018/08/27(月) 16:29:13.02ID:VuJs8kRo
>>539
sigsetjmp(), siglongjmp() ってのがあるので、そっち使った方が良さそうではあるな。
2018/08/27(月) 16:33:51.80ID:J1p6Vf0T
Linuxとかならpthreadがあるのでわざわざ自分でディスパッチャ作ることはないと思うけど、組み込み用に簡易的に作ることはあるかもね。

俺は組み込みならprotothreadsのほうがシンプルで好き。
2018/08/27(月) 17:20:53.65ID:cJbIVPPr
#include <signal.h>
void (*signal(int signum, void (*sighandler)(int signum)))(int signum);

この宣言が読めない
2018/08/27(月) 17:30:35.88ID:vY3QDx2y
signal 関数名
signum 第1仮引数名
sighandler 第2仮引数名

sighandler ポインタ
*sighandler 関数
signum 第1仮引数名

signalの返却値はsighandlerと同じ型
2018/08/27(月) 18:31:36.73ID:C1HpzEi0
>>524
思い浮かばないってのがなかなか考えられない
ていうか、
for/while/do while 以外もbreakで抜けられたら良いと思ったことが私もある


>>525
なぜgotoは使いたく無い?
という質問の答えも聞いておかないと
コーディング規約なのか宗教なのか
gotoの使い方を知らないだけなのか
2018/08/27(月) 18:49:30.60ID:C1HpzEi0
>>536
OSのタスク切り替え処理
ブートローダーからアプリケーションへのジャンプ
リセット
例外処理
2018/08/27(月) 19:22:28.99ID:FN2jn8ES
>>546
全て別の方法で実現しちゃうので、俺的にはlongjmpの必要性を感じないかな?
2018/08/27(月) 19:30:11.24ID:m5aHtIH2
>>530
高度すぎてなに言ってるかわからん
2018/08/27(月) 19:46:09.70ID:nZJhjhuf
まあデータの損傷をいきなりデータ構造そのものの破綻に結びつけるのは些か強引な論理展開ではあるな
2018/08/27(月) 19:55:16.65ID:C1HpzEi0
>>547
関数ポインタ
アセンブラ
スタック書き換え

このどれか?
2018/08/27(月) 20:08:36.09ID:FN2jn8ES
>>550
こんな感じ。

OSのタスク切り替え処理
→普通にOSの機能を使う、カーネルなしで簡易ディスパッチャ実装はpthread

ブートローダーからアプリケーションへのジャンプ
→アドレス固定ならアドレスを関数ポインタにキャストしてジャンプ、またはインラインアセンブラ

リセット
→周辺機能やbssやdataセクションも初期化したいのでWDT等のCPUリセット機能を使う

例外処理
→密結合を避けるためオーソドックスに返り値で判定、最後にgoto使うかも?

そういや例外処理longjmpで思い出したけど、一昔以上前のCマガジンにマクロでC++と同じようなtry〜catch構文実装方法の記事があったけど、確かにそのマクロ内ではsetjmp/longjmp使ってたわ。
マクロでカプセル化してれば例外処理で使うかも。
2018/08/27(月) 20:17:29.99ID:C1HpzEi0
カーネルなしでpthreadの意味がわからん
2018/08/27(月) 20:21:53.00ID:FN2jn8ES
>>552
あ、まちがえた。
pthreadじゃなくてprotothreadsね。
2018/08/28(火) 15:16:05.31ID:wM2MhSxp
http://techtipshoge.blogspot.com/2011/02/blog-post.html
このサイトで、書いてることは正しいと思うしし、実際こうなるんだけど、俺の頭悪いせいでわからない。

駄目な例のsetStr(a)の a は、 &a[0] という”アドレス”を渡してる訳ではないんでしょうか?
なんで駄目な例だと上手くいかないのかという理屈がわからない・・・
2018/08/28(火) 15:16:57.00ID:wM2MhSxp
あ、レスして気づいたけどcoutがあるってことはc++なのかな?
まあこれはprintfってことにしといてくださいw 重複質問になりそうなのでこちらで処理したい。
2018/08/28(火) 15:27:14.25ID:cEEOiaf2
newもC++のキーワードなんだけど。。

関数に実引数のポインタを渡すとその値が、対応する仮引数に代入(コピー)され、以後、仮引数は変数のように使える。
仮引数の値を変えてもコピーが書き換えられるだけで元の実引数の値には影響しない。
書き換えられるようにするには、書き換えたい場所のアドレスを渡して、*演算子か、[]演算子を使わないといけない。
2018/08/28(火) 15:27:46.08ID:10z9ufr/
駄目な例のa = new char [8];はmainのaの複製への代入なのでmainのaはNULLのまま
良い例の*a = new char [8];はmainのaそのものへの代入なので期待した結果が得られる
2018/08/28(火) 15:37:02.95ID:cEEOiaf2
関数呼び出しのとき、実引数がどこにコピーされるかというと、「スタック」という積み上げ式のメモリーブロックか、一時的なCPUレジスタが使われる。
インラインではない関数呼び出しにおいては、関数の戻り先のアドレスと、仮引数のデータがスタックに積み上げられる。
積み上げ式だから、自分自身の関数を呼び出しても動作する。これを「再帰呼び出し」という。
2018/08/28(火) 15:39:32.69ID:cEEOiaf2
スタックの積み上げには限度がある。限度を超えると、スタックサイズが拡張されたり、異常終了する。
スタックの積み上げが限度を超えて異常な状態になることを「スタックオーバーフロー」という。
2018/08/28(火) 15:52:37.71ID:wM2MhSxp
すません。私の質問が曖昧だったので追加で

void setStr(int *a) {

a[0] = 10;

}

int main() {

int a[10];


setStr(&a[0]);
     cout << a[0] << endl;

return 0;
}

例えば、この場合は、setStr(&a[0])として、その後、関数内でa[0]=10;と値を代入すればちゃんと 10 が出力されます。
前のHPの失敗例も同じくsetStr(a)としてアドレスを渡し、受け取りはポインタ変数なのに値は変わらない。
単に数値か文字列かの違いなんでしょうか?
2018/08/28(火) 16:00:50.42ID:Gzofmim2
とりあえず一度、配列とポインタに対する余計な先入観を捨てて素直に元サイトを読み込めば理解できると思うよ
一つの考え方に囚われ過ぎてると思う
2018/08/28(火) 16:05:47.55ID:10z9ufr/
void setStr(char **a) これを
void setStr(int *a) こう読み替え

char *a = NULL; setStr(&a); これを
int a = 0; setStr(&a); こう読み替えてみそ

つまり char* → int と読み替えるんだ
ポインタ変数とアドレスは違うという話は
整数変数と整数は違うという話と同じだ
2018/08/28(火) 16:17:43.85ID:LgBUyhOe
まあスタック使えとは規格に書いてないんだけどね
2018/08/28(火) 16:35:30.28ID:wM2MhSxp
ああ分かった!
俺は自分で勝手に「char型のポインタ=文字列だ」と思い込んでて、そのせいで混乱してただけでした。
思い込み怖い・・・

void setStr(char *a) {
a[0]='a';
}

int main() {
char a[] = "test";

setStr(a);
cout << a << endl;
return 0;
}

これで「aest」と表示されたからピンときた。確かに失敗例はポインタ変数を渡しているだけだw
ありがとうございました。
2018/08/28(火) 18:19:39.20ID:4ROMapnq
>>563
そりゃそうだよ、世の中にはスタックを持たないマシンもあるからな
2018/08/28(火) 18:33:43.92ID:oY+WdDFv
ハードウェアスタックを持たなくて再帰呼び出し出来ないうんこ環境があるね
2018/08/28(火) 18:38:07.52ID:h1lwFjom
そういうのは自分で値を積み上げるように作るしかないな
2018/08/28(火) 18:45:10.17ID:Gzofmim2
そういえばずいぶん昔に昔ながらのBASIC言語でクイックソートを実装したときに当然サブルーチンの再起呼び出しなど使えないので
自分で似たようなことをやったなあ
というか確か何かのプログラム認定試験の定番の出題テーマだった気がする
当時必死に勉強してたことを思い出した
2018/08/28(火) 18:45:55.20ID:Gzofmim2
再起ってなんだ再帰の誤変換
2018/08/28(火) 18:47:51.41ID:h1lwFjom
再帰 不能
2018/08/28(火) 19:51:12.99ID:zI7irPVs
ぴゅう太なんてレジスタがなかった
2018/08/28(火) 19:56:09.59ID:c8HqOUoV
>>571
そんなアホな…

うわ、ホントだ。汎用レジスタは全て外部RAMにマッピングされてたのね。
2018/08/28(火) 20:04:33.36ID:10z9ufr/
制御記憶を主記憶とシェアするアーキテクチャはそんなに珍しくない
2018/08/28(火) 20:09:30.18ID:c8HqOUoV
普通にR0とかのレジスタ名ついてるんだけど実体は内蔵RAMにマッピングされてるアーキテクチャならよく見るけど、外部RAMってのは初めて見たわ。
今もこういうアーキテクチャのCPUあるのかな?
2018/08/28(火) 20:15:00.09ID:Gymzh0gE
ない
2018/08/28(火) 20:25:08.96ID:10z9ufr/
ぴゅうたって内蔵RAMなんだっけ
2018/08/28(火) 20:28:21.23ID:c8HqOUoV
>>576
wikipediaによると
ROM 内蔵20Kバイト RAM CPU内蔵256バイト/TMS9918用16Kバイト
だそうだ。
2018/08/28(火) 20:53:39.14ID:UQgP5OTn
>>573
制御記憶ってマイクロコードを入れるところなんだが…
主記憶と共用してる奴なんてあったか?
2018/08/28(火) 20:58:39.83ID:10z9ufr/
>>578
必ずしもマイクロ【コード】を入れるところじゃないんだけどね
たとえばメインフレームではDIAGNOSE命令で制御記憶を目的外使用なんてのをやってたよ
それやってるときはTestインジケーターが点灯することになってて
2018/08/28(火) 21:38:04.13ID:UQgP5OTn
>>579
> たとえばメインフレームではDIAGNOSE命令で制御記憶を目的外使用なんてのをやってたよ
そんな特殊な例出されてもなぁ w
そりゃ記憶装置だから他の物を入れることはできるよ
だから何? って話だけどな

> それやってるときはTestインジケーターが点灯することになってて
で、主記憶と共用ってどこのアーキテクチャなんだ?
2018/08/28(火) 21:54:20.28ID:d5vKjLdu
>>580
やめたれ w
2018/08/28(火) 22:02:06.14ID:lp3F9A9k
それってセキュリティ上問題にならないのか?
2018/08/28(火) 22:15:00.65ID:d5vKjLdu
いまはやりのcore iのバグみたいな?
2018/08/29(水) 23:07:37.73ID:E6lvAa/y
メルトダウン事件移行もアップデートの度にどんどんコンパイルとか画像縮小なんかの処理が遅くなってる気がする
もう怖くて淫照は買えない
2018/08/30(木) 05:50:33.67ID:zs5ycFHj
ベンチマークしてる?
2018/08/30(木) 08:20:17.62ID:cD6Bz7+B
>>582
そりゃなるよ
命令の動作を書き換えるんだから何でもできちゃう
なのでDiag関連の命令はCE(カスタマーエンジニア)モードでしか使えないとかなってたはず
今時のCPUでもエラッタ対策としてマイクロコードの書換えするけどコード自体は暗号化されてる
この暗号化キーが漏れたらえらいことになると思う
2018/08/30(木) 10:16:53.98ID:zs5ycFHj
X'83は単に特権命令ってだけだぜ
2018/08/30(木) 12:25:33.09ID:cD6Bz7+B
マシンによって違うのか?
M-180HはCEモードでないと動作しなかったが
2018/08/30(木) 12:43:00.44ID:zs5ycFHj
そういうことだね
俺んとこではPWOFFするオウンコードとかできたし
2018/08/30(木) 20:09:52.14ID:cD6Bz7+B
それマイクロ関係ないだろ
2018/08/31(金) 06:31:31.30ID:QWemr4wG
すみません思い切り初心者の質問です。
printf("%s: abc", str);
↑こういう文が abcのみが変わる形で(str変数は変更されません)
沢山登場するプログラムを作っており コピペが面倒だしバグの温床になりそうなので
#defineマクロなどを使って引数にabcを指定すると上記の文がまるごと出力されるようにしたいと思いました。
そこで
#define PR_POS(_pos) printf("%s: _pos", str)
という定義を作ったのですが恐らく引用符の中身は変更されることはないので
#include <stdio.h>
#include <stdlib.h>

#define PR_POS(_pos) printf("%s: _pos\n", str)

int main(void) {
char str[256] = "text";
//printf("%s: abc\n", str);
PR_POS(abc);

exit(EXIT_SUCCESS);
}
というプログラムを作っても実際コンパイルしたものを実行すると
text: _pos
という望んでいない出力が返ってくるだけです
これを
text: abc
という出力にするにはどうすればいいでしょうか……。
2018/08/31(金) 06:43:34.91ID:jQ6ZKbRR
>>591
#define PR_POS(_pos) printf("%s: " #_pos "\n", str)
でいけるはず
詳しくは
プリプロセッサ 文字列化演算子
とかでぐぐれ
2018/08/31(金) 06:44:40.48ID:Df6BGOL7
#define PR_POS(_pos) printf("%s: " #_pos, str)
2018/08/31(金) 06:45:58.45ID:Df6BGOL7
かぶった
しかもまちがった

>>593は無視して
595591
垢版 |
2018/08/31(金) 07:04:03.05ID:QWemr4wG
>>592
うわあああ! ありがとうございます。
正直 検索しても検索しても一向にそれらしき答えが見付からなかったんで
もう方法がないのかなとか思ってました……。
文字列化演算子なるものがあるのですね。用語まで教えていただいてほんとうに感謝しています。

しかもC99でも定められてるっぽい?
(gcc -std=c99 -Wall -Werror -pedanticで警告がなかった)
嬉しいです。これで随分すっきりしたソースコードになりそうです!

>>593さまもありがとうございます。
2018/08/31(金) 07:18:20.44ID:4o8e5lPA
#include <stdio.h>
#define DEBUG(fmt, ...) \
fprintf(stdout, "%s:%d #%s " fmt "\n", \
__FILE__, __LINE__, __func__, ##__VA_ARGS__);

初心者ならこのマクロを覚えておくと良いぞ。誰もが一度は使うはず。
2018/08/31(金) 07:26:18.95ID:jQ6ZKbRR
>>595
> しかもC99でも定められてるっぽい?
X 3010:2003 (ISO/IEC 9899:1999)
6.10.3.2 #演算子
制約
関数形式マクロの置換要素並びの中にある各#前処理字句の次の前処理字句は,仮引数でなければならない。
意味規則
置換要素並びの中で,仮引数の直前に#前処理字句がある場合,対応する実引数の前処理字句列のつづりを含んだ一つの単純文字列リテラル前処理字句によって,#前処理字句と仮引数を置き換える。(後略)
http://kikakurui.com/x3/X3010-2003-01.html
2018/08/31(金) 07:48:00.90ID:QWemr4wG
>>596
すいません。初心者なのにめちゃめちゃ上から目線みたいになってしまうんですが
assert()を使わないのはなぜですかね。
POSIX C99でも定義されているので ほとんどどのコンパイラでも処理できると思うんです。
2018/08/31(金) 08:16:53.54ID:4o8e5lPA
>>598
マクロの紹介だけだから。
デバッグ方法としてならassertを多用したほうが良いぞ。
2018/08/31(金) 08:23:18.46ID:LcHwdHfr
フィールドのエラーログ用に>>596みたいなコードをリリースバイナリにも埋めることがあるけど
その場合はassertじゃ役に立たないんだよな。
2018/08/31(金) 08:31:20.23ID:uM5wy4o0
斜め読みだけど、abcが変わってstrが変更されないならabcの方を文字列変数にしてprintfすれば良いんじゃね?
2018/08/31(金) 08:33:49.15ID:CKe+Ima+
>>596
可変長引数マクロはgccだけって記憶があったけどC99規格で使えるんだね。
「可変部の実引数が0個の場合に……」のgcc拡張とゴッチャになってた模様。

>>598
警告を表示しても動作を止めたくない場合には重宝するよ。
デバッグ中に「ここまでは処理が通過した」と確認する時とか。
2018/08/31(金) 08:40:41.19ID:QWemr4wG
>>602
なるほど。
assert()関数だと引数の結果が0の場合問答無用で停止してしまいますもんね。
2018/08/31(金) 09:08:12.10ID:9zTxkh/J
本番のコードと差が出て邪魔なのでassertはあまり使いませんね。
どうせデバッガ使うというのもあるし。
2018/08/31(金) 09:17:03.63ID:QWemr4wG
>>604
本業の方の意見はほんとありがたいです。
コンパイルエラーと違ってassert(3)は実行時にエラーを吐くので同じ「実行するときに診断する」プログラムでassert(3)より高機能なデバッガ(GDBとか)を使うということですか?

---
>>591の処理ですが以下のように書き直したところ望み通りに動きました。
みなさまありがとうございます。感謝します。
#include <stdio.h>
#include <stdlib.h>

#define PR_POS(_pos) printf("%s:" #_pos "\n", str)

int main(void) {
char str[256] = "text";
//printf("%s: abc\n", str);
PR_POS(abc);

exit(EXIT_SUCCESS);
}
2018/08/31(金) 10:04:04.85ID:Qsv+Vg4k
assertの使い道って「ここでは必ずhogeになる!」という意志をコードに残すという意味はあるかな。
言ってるとおりで動かすときはgdb使うし、開発中は単体テストで同等以上の確認するしで、実用性は今はあまり無いと思いますね。
2018/08/31(金) 11:00:23.86ID:mNRFahys
assertはどっちかつーと単体テストでよく使う
2018/08/31(金) 12:32:32.62ID:QMdn6GpG
本番コードでもassert使うかな
ハードエラーみたいなのはカバーしきれない
2018/08/31(金) 12:51:53.38ID:jQ6ZKbRR
>>606
> assertの使い道って「ここでは必ずhogeになる!」という意志をコードに残すという意味はあるかな。
assertion の意味は主張だからむしろそれが正しいとも言えるな

> 実用性は今はあまり無いと思いますね。
最初作るときはそうでも改修時に全然触ってない所のassert()に引っかかることもあるから俺は基本入れてる
2018/09/02(日) 07:11:07.60ID:667Fbrpy
int a = 42;
a = a++;
↑これがコンパイルエラーになる理由って
「左辺aに対する代入と右辺aに対するインクリメントのどちらの演算を優先して処理するか不定である為」
で合ってますか? 不定じゃなくて未定義かも……。
2018/09/02(日) 07:29:52.76ID:fa3EYjvI
エラーになるか? 警告ではなく
2018/09/02(日) 09:00:51.15ID:667Fbrpy
>>611
-Werrorとかにしてました
613611
垢版 |
2018/09/02(日) 09:07:14.14ID:667Fbrpy
>>611
あれ。すいません。よく分からなくなりました。
$ gcc -pedantic -std=c99 -Wall -Werror -O2
でコンパイルするとエラーになり停止しますが
$ icc -std=c99 -Wall -Werror -O2
でコンパイルするとあっさり通りますね……。
2018/09/02(日) 09:27:27.59ID:pzXMyV5h
>>610
未定義っす (>>1 C FAQ の 3 章を参照してください)
蛇足ながらシーケンスポイントの間でオブジェクトを変更できるのは高々1回だけとか、そんな感じのルール
>>613
gcc の -Werror オプションは警告をエラー扱いにするっす
2018/09/02(日) 09:59:41.19ID:GR8jnF/5
未定義だからコンパイラは何をしてもいい
2018/09/02(日) 10:00:57.15ID:667Fbrpy
>>614
ありがとうございます。
ちなみにicc (Intel(R) C/C++ Compiler)で-Wallおよび-Werrorオプションを設定したときは
警告もなにも出力されることなくコンパイルに成功してしまったんですが
理由とか分かりますかね。すいません。変な質問で……。
2018/09/02(日) 10:19:45.38ID:667Fbrpy
>>614
あと,おっしゃる通り(すくなくともC99では)未定義でした。ありがとうございます。
> 直前の副作用完了点から次の副作用完了点までの間に,
> 式の評価によって一つのオブジェクトに格納された値を変更する回数は,高々1回でなければならない。
> さらに,変更後の値の読取りは,格納される値を決定するためだけに行われなければならない。
(JIS X 3010:2003 p.48; 参考 https://dotup.org/uploda/dotup.org1632204.png
2018/09/02(日) 11:28:11.60ID:owKXNyzr
>>610
そういう文法的になことには今は拘らない方がいい。(これは他言語学習者の方が酷いが)
上達の妨げにしかならない。

プログラミング言語は、「正しく書いたときに正しく動作する」ようにしか設計されていない。
特にCはそうだ。
意味不明なことを書いたらだいたい全て「未定義」であり、
意味不明なことを書く奴が悪い、ということになっている。
そしてそれが「未定義」と覚えることも、実質的な意味はない。
そんなコードはすぐに修正され、存在しないからだ。
実際、 a = a++; なんてコードは、どのOSSにもないはずだ。

この意味で、Cは全くの素人の入門者用ではない。
例えばC#はそこら辺厳しい言語で、そういった意味不明な書き方は全てコンパイルエラーにされるはず。
(さすがにその例では知らんが、例えば「未初期化の変数を使用」とかがエラーになる)

というか、マジでそのレベルならC#やった方がいい。
文法エラーなんてサジェストが出てOK押したら自動的に修正してくれる。
お前がどんな環境でやってるのかは知らんが。

ただ、こういった無駄な遠回りをしなくて済むだけでも、君にとってC#は有効だと思うよ。

つか、初心者は全ての文法を押さえないといけないと勘違いするようだが、それは間違いだ。
自分が使うだけの文法を押さえ、さっさと使うべきだ。
お前だって日本語の全ての漢字が読めるわけでもないのに日本語を使ってるだろ。
プログラミング言語も同様で、手段でしかないのだから、文法を一通り確認したら、
さっさとゲーム等何でもいいから作れ。
ネタがないのならそれはそもそも今プログラミングを学ぶ必要がないとも言えるし、
それでもやりたいのならラズパイでも買ってきてLEDチカチカでも目指せ。
文法を学ぶことが目的になってはいけない。それは完全に空回りだ。
2018/09/02(日) 11:39:01.45ID:mdI4MGys
やりたいことはシンプルに書けよってことだな。
最終的に a にどうなってほしいのか、それってもっと端的に書けないの?ってこと。
Cオタクになるのが目的じゃなければな。
2018/09/02(日) 12:11:10.31ID:owKXNyzr
(ちなみに補足)>>610
初心者には理解不能だと思うが、
「文法で許されていることが全て許される」環境なんて実質的に存在しない。
だから文法のコーナーケースについてはそもそも覚える必要がない。
(とはいえ、肝心のK&Rがフリーダムすぎて…ってのはあるが)

これは小説→ラノベの流れと同じで、
美辞麗句の技巧に走る必要はなく、簡単な文を書き連ねて面白い筋を書け、ということ。
プログラミングにおいてはこれが徹底していて、
同じ物なら、簡単な方が『常に』いい、ということになっている。

ただ、どこからが複雑なのか?というのは議論になる。
例えば自然言語で韓国が漢字を廃止した際、
「停留所」を「ばすが とまる ところ」と書き換え、老人が「舐めとんのか!」と切れた。
実際、全員が読める漢字を「もっと簡単に」という理由で平仮名に書き換えられても困るだろ。
丁度これと同じ(だが方向は逆)で、
新しいプログラミング言語は比較的すんなり書ける文法が用意されており、
それを使うべきかどうかでは揉めたりしている。
ただ、Cは古いのでまどろっこしい文法しかなく、ベタな書き方しか出来ない。
だから比較的この論争に巻き込まれることはないはず。
(それ以前に文法セット自体が小さくて、え?これだけ?のはずだが)

>>619
天然と養殖では学びのベクトルが逆なんだよな。

天然: 1を足したい → a++ と書くのか
養殖: a++と書くと → 1が足されるのか

結果、要因側をenumすると文法一覧になるのが養殖で、これが間違いの元だ。
そしてそれを馬鹿正直に一つずつ潰すから文法エリートになっていく。
そうではなく、要因側のenum結果はやりたいこと一覧になって、全部揃えばゲームが作れる!が正しい。
2018/09/02(日) 12:24:17.27ID:667Fbrpy
>>620
ちょっと反論があります。正直Cどころかプログラミング初学者なのですが……。

要するに私は養殖≠ナあり,そのような学び方では成長しないと仰りたいわけですよね。
まあ確かに自分でも「規格厨」というか,衒学的な性格をなのは自覚してます
しかしプログラミング言語というのは自然言語とは違う面が多々あると思います。
そして「文法を網羅すべきか」という点においては特に違うと思います。
プログラミング言語は少なくとも概念においては文法に正確に従えば定められた動作を確実に行ないます。
日本語の文法を遵守して話しても考えが伝わらないのとは全く異るところです。
だから私はプログラミング言語においては先に(かなり厳密に)文法を学ぶべきであり,
「文法を学ぶ」ことのなかには未定義動作に関する諸々の知識を習得することも含まれていると考えます。

偉そうにすいませんでした。まあ上手くいかなければまた考えを改めるつもりではいます。
2018/09/02(日) 12:32:31.40ID:mdI4MGys
やりたいことを素直に書いたつもりで未定義な文法になってしまうなら、もっと論理を考えた方がいいかも。
やりたいことを行う手順を整理できてないってことだと思うよ。
a = a++; ということが結局どういう動作するのかを知ることより、何をしたくてそういう(矛盾をはらむ)書き方になったのかを自己分析した方がいい。
もちろん基本的な文法は勉強しておく前提はあるよ。
おれは養殖とか天然とかは分からんけど。
2018/09/02(日) 13:02:03.12ID:gypPfsRT
Cは文法的にはコードのデザインをほとんど規定しないからね。
そういう意味では頑張って覚えるほどでもない。まあ量も少ないので覚えてもいい。
でも古いコードとの互換性にこだわる様なおっさんにはならんでくれやという感じ。
2018/09/02(日) 13:06:08.54ID:nnaQ2akS
>>621
あなたの言うことにも一理ある。

でもこの板にいる人は1つの言語しか使えない人って少数派で、たいていは3、4つまたはそれ以上の言語を操るマルチリンガルな人が多いと思う。
んで、その人たちはどうやって新しい言語を使えるようになるかって言うと、1つの言語をマスターすると(Prologとか特殊な言語は除いて)他の言語も方言みたいなもので、書き方の問題だけなことが多いのね。
その際には特定言語の重箱の隅をつつくような知識が必要なわけではなく、むしろ最大公約数的な知識、もっと言うと言語に依存しない設計力のほうが大事になってくる。
なので、特定言語のあまり細かいルールにこだわり過ぎないほうが良い、という経験論での意見は間違ってはないと思うよ。
2018/09/02(日) 13:21:05.23ID:mdI4MGys
そうそう、しいて文法を覚えるなら適切に const を指定するクセを付けてほしいな(const に限った話ではないんだが)。
文字列を引数で受ける箇所全部が char* になってるコードを見るとクラクラするw
2018/09/02(日) 13:50:09.03ID:owKXNyzr
>>621
反論自体は自由にやればいいんだよ。それが匿名掲示板のメリットなのだから。
ただ、書かれている内容については吟味しないといけない。
その中には君にも峻別出来る内容もあるはずだから。
(というか、こっちが君にも分かる範囲で《客観的な範囲で》話せばいいのだが)

事実から言うと、C言語は『当初から』バリバリの実用言語であり、今も現役だ。
これは同世代の他言語とは全然違う。
だから、普通に書いてれば「未定義」なんてのに命中するはずがないんだよ。
そんな言語、使い物にならないだろ?

次に、歴史も長いのだから、何をどうやったら嵌るかのノウハウも溜まっている。
それの集大成がコーディングルールであり、例えば goto 禁止論だ。
これについても是非はあるが、これまでの経験をタダで享受する気なら、乗った方が得だ。
そしてそれに従っておけば大体全て「未定義」は回避出来る。

具体的に言えば、警告レベルを一番か二番目に厳しい状態で使って、警告についてはほぼ全部直し、
google等「コードを実際に書いている連中」のルールに従って書けば、そもそも未定義なんて踏まない。
それらはそのように整備されているから。

業務で「コーディングルール無し、警告も全部無視してよし」なんてのはあり得ないし、
仮に個人レベルでそうでもバグが取れなくて無駄に苦労するだけ。
だから結果的に「未定義」なんて気にする必要ないんだよ。
一般的な環境で普通に書いてれば命中しないし、知る必要もない。
一通りも書けない初心者なら特にそう。他にやることはいくらでもある。

君は休日にプログラミングをやろうとしているのだから、本来は「天然」なんだよ。
それを自分で「養殖」型のカリキュラムにして、無駄に上達しにくくなってる。
そこが勿体ない。
君が何の為にCを学ぶのかは知らないが、もっと直接的にその結果を目指すべきだ。
とりあえず学ぼう、では全く上達しないんだよ。
それは日本人の英語でもそうだろ。使わないと上達しないんだよ。
2018/09/02(日) 13:50:53.63ID:667Fbrpy
>>624
確かにそうですね。先に述べた通りプログラム全般に暗いのですが
JavaやPythonなども大まかな構造(サブルーチンとか演算体系とか)は
似ているかなと感じました(見当違いなこと言ってるかも)。
もっと抽象的な立場になったほうがいいですかね。

>>625
アドバイスありがとうございます。
ggってみたところconstはその重要性の割に実務で使われていない傾向にあるみたいですね。
しかし役割を考えると,特に保守の面で,積極的に使うべきだなと確信しました。
「ここは固定された値代入を想定している」という意図を明確にできるってことですよね?
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況