トップページ⇒tech
1001コメント240KB

C言語の質問スレッド<42>

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
C言語に関する質問はここでしてください。

問題をちゃんと切り分けて、Cの話かそうでないか洗ってから質問してくれ。
というより、聞く前に一応 Web で検索しろ。
コンパイラを探してるなら >>2 を見ろ。
過去ログ(DAT落ちあり)なら>>3-100あたりにあるかも。

GUIとか、C標準でできない事の質問は使ってる開発環境のスレに逝ってくれ。
ソース丸投げ、宿題、書籍 は専門の別スレがあるからそこへ逝ってくれ。

未定義・処理系依存ネタはご遠慮ください。
誰かが(故意にではなく)それらの書き込みをしても、いちいち突っ込まないでください。
規格オタクはこのスレッドには必要ありません。論争したかったら独自にスレッドを立ててそこでやってください。


C FAQ 日本語訳
http://www.catnet.ne.jp/kouno/c_faq/c_faq.html
comp.lang.c FAQ(英語の原文)
http://www.eskimo.com/~scs/C-faq/top.html
Cプログラマ必読 ・プログラミング言語C(通称 K&R)
http://www.amazon.co.jp/exec/obidos/ASIN/4320026926/
推薦図書/必読書のためのスレッド PART6
http://pc3.2ch.net/test/read.cgi/tech/1033207156/


前スレ <41>
http://pc3.2ch.net/test/read.cgi/tech/1036876790/
0756デフォルトの名無しさんNGNG
>>755宿題スレへ行けと言われる。理由:ここは宿題を教える場所では無いから。馬鹿にされる理由:汚ないプログラムだから。煽られる理由:馬鹿な質問をするから。無視される理由:飽きられたから。
0757デフォルトの名無しさんNGNG
>>755
答え: >>750-754
理由: >>750-754 が現に存在するから。
0758デフォルトの名無しさんNGNG
「答えよ」なんて言われてせっせと答えるのは試験位なもの。
普通はそんな糞質問に答える義務等、無い。
cより前にk語を覚えよう。
0759デフォルトの名無しさんNGNG
まあ >>750 のコードは、exit() がスキップされるのを期待したんだろう。

s4[400] は、exit() の呼び出し元のアドレスを格納したスタックの直前の領域に確保される。
ANSI では int a4[400]; を宣言した時に a4[400] にアクセスできる事を保証しているので、
実際には sizeof(int) * 401 バイトの領域が確保される。
つまり、a4[401] は呼び出し元のアドレスが格納されているので、これを書き換えてやると関数から
戻る先が換えられる。

なお、int s4[N]; の時に s4[N + 1] にアクセスすればいいので、N == 400 である必要は特に無い。
あと、引数は呼び出し元のアドレスより後のスタックに格納されるので、いくつあるかは関係無い。


が、これがうまくいくのは余程限定された状況でだな。
「i386 上」 だけでは成り立たない。

コンパイラが、変数を必ずスタックに、詰めて確保する事。
sizeof(int) == sizeof(void (*)()) が成り立つ事。
操作した戻り先のアドレスに、必ず安全なコードが書かれる事。
コードが最適化されない事。
デバッグモードでコンパイルされない事。

これだけの条件が揃う事はあまりない。
よって >>750 はクソ。
0760デフォルトの名無しさんNGNG
なんでexit(1);のコードが16byteってわかるん?
0761デフォルトの名無しさんNGNG
>>760
だから、それすら確定していない。
> 操作した戻り先のアドレスに、必ず安全なコードが書かれる事。

特定のコンパイラが吐いたコードのリスティングを取るか逆汗して
調べたんだろ。
ちなみに VC6 では、call _exit、pop ebx、pop esi、pop edi が
スキップされる。
push に対する pop がスキップされるのは、malloc() に対する free() が
スキップされるのに等しい。
0762761NGNG
ちなみに MS-C6 では、16 を足すと main() からはみ出てしまうので、
はっきり言って何が起こるか分からない。
0763デフォルトの名無しさんNGNG
今時i386のPCなんかネーヨ
で終わりにしたいな(w
0764761NGNG
もう一つ追加。
VC6 では、無条件の exit() があると、それより後ろを全部カットする。
だから printf() は結局実行されない。
0765デフォルトの名無しさんNGNG
returnはまだしも、単なる一関数にすぎないexitでそこまでしてくれるのか。
まあgccもgetsを使うと危険だと警告してくれたりするけど。
0766デフォルトの名無しさんNGNG
今回も伸びた割には内容の無いスレだったな
0767デフォルトの名無しさんNGNG
まあ、標準ライブラリの関数をネイティブのステートメントとして解釈する処理系は
多いと思うよ。
VC なんか ZeroMemory() をインライン展開したりするし。
0768デフォルトの名無しさんNGNG
>>761
test()の実引数のクリアはどこ行ったのよ?
add esp,16
0769デフォルトの名無しさんNGNG
あのコードを VC に放り込んだ場合、実引数なんてものは出てこないのだが。
最適化 Off の状態で。
ただし、main() と test() を別々にコンパイルするなら別。
0770768NGNG
実引数って間違った表現だな。パラメータのことね。
0771768NGNG
>>769
そうだったんか。staticでもないのに?
ちょっとこっちでもやってみるね。
0772デフォルトの名無しさんNGNG
出てくるじゃん
0773デフォルトの名無しさんNGNG
「向こう」 が age らけちゃったから
こっちも唐揚げ
0774768NGNG
こっち(VC5)では最適化をOFFにしても何してもパラメータが出た。

つーか、test()がstaticでない限り、外からも呼ばれる可能性が
あるので、test()とのパラメータ受け渡しは省略できるはず
ないと思うんだが。俺が変なのかな?

push 3
push 2
push 1
push 0
call _test
add esp, 16
push 1
call _exit
add esp, 4
0775769NGNG
>>774
スマソ、もれの勘違いだったようだ。
(問題を簡単にするために仮引数無しのバージョンのソース書いてた)
で、

>>759
> 引数は呼び出し元のアドレスより後のスタックに格納される

外からいくら引き渡されても、結局スタックの一番先頭にあるのは戻り先のアドレス。
test() はそれを使って return するだけ。
スタックに大量に積んだ引数の始末は、その後に呼び出し側がつける。

よくわからないなら、(あなたはアセンブリコードが読めるようなので) 実際に
そうしてみて確認してみればいい。
引数が全く指定されなくても大量に指定されても、動作に影響の無いコードに
なってるはずだ。
0776デフォルトの名無しさんNGNG
(void)printf("%d\n"a);
みたいにやって返値を無効(?)にしてるのかどうか
わかりませんが
これが呼び出し側に与える影響というのは
どういうものなのでしょうか?
返値を何かになんらかの変数に代入してる
ようなことは見受けられませんので理由がわかりません
0777デフォルトの名無しさんNGNG
(void) がする事は何も無い。
付けても付けなくてもコンパイラは同じコードを吐く。

戻り値は一般に、CPU 内部の特定の作業領域に保存される。
(x80 なら EAX レジスタ)
その後のプログラムによって、いずれその CPU 内部の特定の作業領域は
別のデータで上書きされて消える。
それだけだ。

その戻り値が変数に代入されていたり式に使用されていれば、上書きされる前に
どこかのメモリ領域か、CPU 内部の他の作業領域にコピーする。
0778デフォルトの名無しさんNGNG
意味ないですよね
bsdのpingとか観てたらそんなコードがありましたんで
そっか
0779デフォルトの名無しさんNGNG
>>778
lintなどのツールに文句を言われないために付けることはある。
0780デフォルトの名無しさんNGNG
>>778
コンパイラの警告を黙らせるためのおまじないだと思う。
0781デフォルトの名無しさんNGNG
ANSI に対応したコンパイラで、戻り値を捨てると警告が出るコンパイラが
あるのか?
0782デフォルトの名無しさんNGNG
unsigned char c;
switch (c) ...
とした時、caseがちょうど0〜255だけあるのに
レンジチェックするコードが出てしまいます。
レンジチェックせずにいきなりテーブルジャンプするように
する方法はないでしょうか?

あるいは「このコンパイラならOK」という情報でも
けっこうです。

今使っているコンパイラはVC6です。
0783デフォルトの名無しさんNGNG
>>782
テーブルジャンプするのにswitchを使うのが間違い
func tbl[] = { func_a, func_b, fund_c, ...};
tbl[c]();
でいいんじゃないか?
0784774NGNG
>>775
あれ?もしかして後半も俺向けの返事?

だったら、
> 引数が全く指定されなくても大量に指定されても、動作に影響の無いコードに
> なってるはずだ。

これは間違い。
関数から戻った直後に引数をクリアするコードが
入っているかどうかによって、
s4[401] += 16; した時の戻り先も変わってくる。
(戻り先アドレスは変わらないが、後続の命令の配置がずれる)

さらに言えば、引数の有無だけでなく、
引数のサイズが256バイト以上か未満かでも
 add esp,バイト数
という命令のコードサイズは違ってくるはず。

つまり、もろに動作に影響する。
0785デフォルトの名無しさんNGNG
>>782
suitch で評価されるのは int 値じゃなかった?
unsigned char で評価されるのは期待できなかったと思うけど。
0786775NGNG
>>784
すまん、漏れの解釈が間違ってた。
「あの場合に限って」 と言うなら、あなたの言う通り。
test() に s4[401] += 16; のような危険なコードが入ってなければ、
漏れの言った通り。
0787デフォルトの名無しさんNGNG
↓ は神
0788デフォルトの名無しさんNGNG
↑は鬼畜
0789デフォルトの名無しさんNGNG
>>782
VC6で試してみたけど、やっぱりチェックコードが入ってるね。

andeax, 255; 000000ffH

チェックコードの直前にこういうコードが入ってるんだから、
チェックする必要ないんだけど、ここまでは考えてないんだろうね。
0790デフォルトの名無しさんNGNG
↑ は神
0791デフォルトの名無しさんNGNG
↓は鬼畜
0792デフォルトの名無しさんNGNG
ウンコ引数にして投げるぞ
0793デフォルトの名無しさんNGNG
#include <stdio.h>
main()
{
int n;
printf("SEISUU=");scanf("%d",&n);
printf("%d\n",n);
}

上記のようなプログラムを実行した場合に
絶対値の大きな整数を入力すると入力した通りの数字が表示されないんですが
何が理由なんでしょうか?あと、表示される数字には規則性はあるんでしょうか?
0794デフォルトの名無しさんNGNG
aaa
0795デフォルトの名無しさんNGNG
>>793
#include <limits.h> をやった上で、INT_MIN と INT_MAX を %d で printf()。
それが int 型で扱える数値の範囲です。
もっと大きな方が必要な場合は、double を使ってください。

limits.h と float.h を調べると、いろいろな型の限界がわかります。
ただし、ここの数値を換えても限界値が変わるわけではないので変えないで下さい。

>>794
( ´,_ゝ`)フーン
0796デフォルトの名無しさんNGNG
>>793
intの範囲外の数値を入力したんじゃネーノ
0797793NGNG
>>795-796
親切にどうもありがとうございます
助かりました
0798JPS ◆M0LaMzf5rY NGNG
getcheって知ってる?conio.hにあるやつ。
あれのWhileループでEOFみたいに
while(c=getche() != 0x1a)
ってやってんだけど、どういう意味?
16進数だよね?
0799デフォルトの名無しさんNGNG
DQNに答えることなど・・・無い!
0800デフォルトの名無しさんNGNG
getche? conio.h? (゚Д゚)ハァ?
0801デフォルトの名無しさんNGNG
>>800
Windows環境でのみ動作するヘッダだYO!
0802デフォルトの名無しさんNGNG
>>801
むしろDOS環境
0803デフォルトの名無しさんNGNG
>>798
実行してみそのままだから
何かキーが押されたらそのキー出力して0x1a(^z)だったら終了
0804デフォルトの名無しさんNGNG
みんなメアド見ないの?
sage のだけクリックしとけば、それ以外が何かしら違うものと色で区別つくから
覗いてみたりするけど。
0805デフォルトの名無しさんNGNG
>>798
while((c=getche()) != 0x1a) {
printf("%x\n", c);
}

こういうコードでも動かしてみて、片っ端から
キーを押せば、どれか分かるんじゃない?
0806デフォルトの名無しさんNGNG
>>804
ボケにマジレスされたからって、いちいち文句言わなくていいよ。
0807804NGNG
間違えて age ちゃった・・・
>>806 らじゃ。
0808デフォルトの名無しさんNGNG
線型構造を勉強してるんだけど
int list_insert(Node *list,int in_number,int value)
{
Node *pos_node=list,*new_node;

if(in_number < 0)
in_number = 0; // 限界値チェック

new_node=malloc(sizeof(Node));
if(new_node == NULL)
return 1;

// 目的位置の一個前まで移動
while(in_number > 1 && pos_node->next != NULL)
{
pos_node = pos_node->next;
in_number--;
}

// 挿入ノードに 元目的位置のポインタ
// および 挿入する値 を代入し
new_node->next = pos_node->next;
new_node->value = value;

// 目的位置の一個前に挿入ノードを連結
pos_node->next = new_node;

return 0;
}
0809808NGNG
この関数のなかでpos_nodeはなんで必要なの?
listをこぴってるから、直接リストをいじるのとかわらないんでないの?
0810デフォルトの名無しさんNGNG
>>808
必要ないです。
かわらないです。
いじょ。
0811808NGNG
>>810
( ̄□ ̄;)!!
listの必要性を考えて小一時間ネット上をうろついたオレって一体・・・
0812デフォルトの名無しさんNGNG
>>811
引数を直接いじると何か気持ち悪い、っていう程度の
理由だと思うよ。
0813デフォルトの名無しさんNGNG
>>812
気持ちはわかるね。たぶん808のソースはどっかのコピペだろうから
分かりやすくしてんだろう。
でもオレも後で見たときの可読性を考えれば、いい事だと思う。
0814デフォルトの名無しさんNGNG
>>813
あなたの文章には鬱病の人特有の言い回しが見れます。
病院に行ったほうがいいと思います。
鬱は必ず直ります。
0815デフォルトの名無しさんNGNG
>>814
うつ病特有の言い回し?
0816813NGNG
>>814
813ですが何か?
0817デフォルトの名無しさんNGNG
だれかいますか?
0818デフォルトの名無しさんNGNG
>>817
いるよ。はあはあ
0819デフォルトの名無しさんNGNG
廃れたね。オレが話題をふるYO!
お前らコンパイラとエディタなんですか?
0820デフォルトの名無しさんNGNG
またその話題かよ。
0821デフォルトの名無しさんNGNG
廃れたねってお前。チャットじゃねーんだからよ。
そんなあせんなよ。
0822デフォルトの名無しさんNGNG
新スレ立って荒らされてるな(プ
0823デフォルトの名無しさんNGNG
構造体listが
{
  int num;
list *next;
}
みたいな線型リストだとして
list == NULLっていうのはどういうことですか?
listの要素全部が0,NULL,'\0'ってこと?
0824デフォルトの名無しさんNGNG
あともういっこ!
線型リストのさいしょの構造体には値は入れないんですか?
0825デフォルトの名無しさんNGNG
>>823
それは実装した人次第だが、一般的にはリストが空。
0826デフォルトの名無しさんNGNG
>>824
最初はポインタの方がすっきりするが、プログラムを組むとわかるが
空の構造体の方が扱いやすい。
0827デフォルトの名無しさんNGNG
>>824
それをおセンチっていいます。
0828デフォルトの名無しさんNGNG
>>827
なつかしいでつね
0829デフォルトの名無しさんNGNG
>>823-826
質問と回答が殺伐としていてよいね

>>827-828
消えろ。
0830デフォルトの名無しさんNGNG
>>825 && 826
サンクス
0831デフォルトの名無しさんNGNG
ある関数が再入可能かそうでないか知りたいのですが、
どうやって調べたらよいのでしょうか? なにかリストみたいなのはありますか?
printfは再入可能でないらしいのですが、僕には理由がわからず。
とにかく、リストがあればとりあえずは楽かなと。
0832デフォルトの名無しさんNGNG
830のレスみて思ったけど、次スレタイはCの演算とかうまく使ってよ。
C++ってなかなかいいセンスしてると思うのは俺だけか。
0833デフォルトの名無しさんNGNG
この静けさ。完全にCを語り尽くした。
0834デフォルトの名無しさんNGNG
>>831
マルチスレッドで使って安全という意味だよね?
C言語の規格自体ではそこまで決まってない。
かといって処理系ごとにまったくバラバラかというとそうでもない。
Unix系のOSなら、Single Unix Specificationという規格でけっこう細かく
決まっている。
http://www.opengroup.org/onlinepubs/007908799/xsh/threads.html
のThread-safetyセクションにリストされている関数はthread-safeで*ない*。
他は全てthread-safe。(printfもthread-safe。)

SUS準拠OS以外なら、処理系のマニュアルを見るしかない。
0835デフォルトの名無しさんNGNG
>>833
今度から初心者の質問すれと
上級者の議論すれにわけたいね
0836デフォルトの名無しさんNGNG
>>835
わけたら余計に人減るじゃん。
0837デフォルトの名無しさんNGNG
>>834
マルチスレッドもありますが、割り込みでprintfを使おうとしてました。
自分なりに調べましたが、
printfはスレッドセーフですが、Async-Cancel-Safe 関数ではないそうです。

いやぁ、よくわかりませんなぁ。素人は割り込むなと言うことですか?w
0838デフォルトの名無しさんNGNG
>>837
シグナルハンドラの中で使いたいのなら、async-cancel safeじゃなくて
async-signal safeなものを探すべきでしょう。
Solarisだとマニュアルに一覧があるけど(90個くらい)。
0839デフォルトの名無しさんNGNG
>>838
SolarisのAsync-Signal-Safe functions一覧
http://docs.sun.com/db/doc/816-0220/6m6nkoroc?a=view
0840デフォルトの名無しさんNGNG
>>837
printfをシグナルハンドラから呼びたいなら、
Async-Signal-Safeでないライブラリ関数を実行中はシグナルをブロックするように
すれば良いんじゃない?

あるいは、シグナルハンドラでは何か情報を変数に書くだけにして、
メインのスレッドでその情報をプリントする。
0841デフォルトの名無しさんNGNG
変数宣言時に
char buf[BUF_SIZE] = "";
と書くとbufの先頭1バイトだけでなくBUF_SIZE全部が終端文字で初期化されます。
これは標準なのでしょうか?
0842デフォルトの名無しさんNGNG
>>841
「終端文字で」ではなく、「残りは、staticな変数と同じように」
初期化されます。それが規格どおりの振る舞いです。
0843デフォルトの名無しさんNGNG
>>842
すばやいご回答ありがとうございました。
0844デフォルトの名無しさんNGNG
volatile int i;
void signal_handler (int s)
{
  i = 1;
  printf ("%d\n", s);
}
↑ここでprintfを呼ぶのと
int main ()
{
  signal (SIGINT, signal_handler);
  while (!i)
    printf ("%d\n", i);
  return 0;
}
↑ここで割り込みを入れるのと、どちらがいけないということですか?
0845デフォルトの名無しさんNGNG
>>844
(断っておきますが、これはC言語の範囲を超えた話題です。)

mainからprintfを呼び出して実行中にシグナルを受け取ったとします。
そのとき、printfが何かの資源をロックしていたとします。
signal_handlerの中からprintfを呼ぶと、デッドロックが起きる可能性が
あります。

汎用の解決策は >>840 の通りです。処理系によっては、シングルスレッドの
プログラムだとprintfが資源をロックしたりしない(したがってデッドロック
が起きない)かも知れません。
0846デフォルトの名無しさんNGNG
>>845
説明して頂いてどういうことか分かりました。
この例では両方で呼び出してはまずいということですね。
割り込みをするプログラムでは、
printfを使ってはいけないのかと思ってしまっていました。
ありがとうございました。
0847デフォルトの名無しさんNGNG
>>798
その前に糞スレの削除依頼出してこいや
話はそれからだ
0848デフォルトの名無しさんNGNG
線形リストだぜははっと、さくさくプログラミングしてたんでしが、、
リンクにポインタを使ってたばかりに、reallocしたら大変な事になって
しまいますた。

問題なのは当たり前だけど、reallocを使う可能性がある時は整数インデックス値
振らんといかんの?ってのは常識!?
0849デフォルトの名無しさんNGNG
>>848
まともな日本語で書いてみてくれないか。
0850デフォルトの名無しさんNGNG
int a[] = {1,2,3,4,5,・・・・・};
と配列を初期化したとき、配列の要素数を簡単に知る方法はありますか?
0851デフォルトの名無しさんNGNG
>>848
ひょっとして、リンクにつながった要素をreallocしようとしてるとか?
(1)大きさが変わる可能性のあるものは、リストにつながってる構造体とは
別にして、リストの構造体からポインタで指す。
(2)双方向リストにして、reallocする前にいったんリストからはずし、
reallocの後で挿入しなおす。
のどちらかで解決。
0852デフォルトの名無しさんNGNG
すまそ。

レコードの増減・並び替えが行われるデータ構造があるんだが、最初にこれを読み込む時
にはレコード総数が分かっているのでmalloc(データ構造*レコード数)という感じでメモリ確保
していたんだ。
で、データの追加・削除・並び替えが発生するんで、リスト構造にし、リンクにはレコード
参照ポインタを使っていたの。
しかし、ここで問題があって、データの追加・削除時にはreallocを使って全データのメモリ
を再確保していたんだよね。
これすると、メモリアドレス変わっちまうんで、リンク情報が役に立たなくなって困ったわけ。

1レコード読むたびにmallocして、追加・削除するたびにもmalloc,freeしていれば
よかったんだけど、レコード数が多いから速度的に難があると思って、全データを
一気にmalloc,reallocしてたの。

漏れ、
非常識なんだろな。
0853デフォルトの名無しさんNGNG
852=848
ですた。
>851 ありがと。
0854デフォルトの名無しさんNGNG
>>852
追加時にreallocする必要はないだろ。(1個ずつmallocすればよい。)
削除時にreallocは無理だろ。(途中だけ削除したりしないのか?)

いずれにせよreallocはやめるべし。
最初にまとめてmallocするのはそのままでもよい。
freeする替わりに、自分で作ったフリーリストにつないで置けばよい。
追加のときはフリーリストから空き構造体を取り出す。フリーリストが
空ならmallocする。
0855デフォルトの名無しさんNGNG
>>850

sizeof(a)/sizeof(i)
■ このスレッドは過去ログ倉庫に格納されています