質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

1912閲覧

_close Windows

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2015/08/10 13:10

Windows2012R2 VS2013 で以下C言語のコードをコンパイルして実行すると
2回目の _close にて例外が発生します。

_close前にチェックを行いたいのですが、方法が判りません。

1)C言語でC++のように例外をキャッチする方法
2)ファイル記述子が有効か判断する手段
があるか教えてください。

元のプログラムが汚く、ファイル記述子をクローズ後に初期化するといった
回避ができず、ファイル記述子のクローズ時に対応できる方法を探しています。
Linuxの場合には、例外が発生せずに -1 がシステムコール(close)より帰ります。
また、どのコンパイルオプションでも同様に対応できる方法を探しています。

int main( void ){
int fh1;

fh1 = _open( "test.txt", _O_RDONLY );
_close( fh1 ); /* 1回目 /
_close( fh1 ); /
2回目 */

}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

実際試してみました。確かに落ちますね。

まず一つ目、発生しているのはC++とかでいう__例外ではありません__。
いわゆるクラッシュとか、アプリが落ちるといった現象です。
プログラムとして想定外の動作になっているため、
C言語であろうと無かろうと、キャッチする方法はありません。
<del>また、C言語には例外という機能そのものがありません。</del>
※ただ、この場合は後述の回避策があります。
MSの独自拡張で例外補足できるようです。しらんかった。

次に、なぜクラッシュするかですが、MSDN:_closeに書いてあるとおり、
fdについて不正かどうかについて、MSDN:パラメーターの検証に書いてある検証を行います。
既に閉じたfdだったなど不正だった場合のデフォルトの動作はクラッシュです。
ただ、この動作は変更できます。
MSDN:_set_invalid_parameter_handlerの記載の通り、
_set_invalid_parameter_handlerを用いて動作を変えれば、クラッシュしません。

C

1#define _CRT_SECURE_NO_WARNINGS 2#include <stdio.h> 3#include <io.h> 4#include <fcntl.h> 5#include <stdlib.h> 6void myHandler( 7 const wchar_t* expression, 8 const wchar_t* function, 9 const wchar_t* file, 10 unsigned int line, 11 uintptr_t pReserved) 12{ 13 // 何もしない 14} 15int main(void){ 16 int fh1; 17 _set_invalid_parameter_handler(myHandler); 18 fh1 = _open("test.txt", _O_RDONLY); 19 printf("1st: %d\n", _close(fh1)); /* 1回目 */ 20 printf("2nd: %d\n", _close(fh1)); /* 2回目 */ 21 return 0; 22}

上のコードはクラッシュせずに

1st: 0 2nd: -1

と出力されると思います。

投稿2015/08/10 14:11

編集2015/08/10 14:16
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/08/10 14:22

ご回答いただき、ありがとうございます。 私の方でも確認できました。 何分古いソースで、手が入れられない状況でしたので 今回のような対応が必要でした。 もちろん、問題は上位層に問題がありますので、時期を見て 修正するようにいたします。
guest

0

try-except で Cでも例外は捕捉できますが、そのように解決すべきではありません。
なぜなら、1回目と2回目のclose の間に、なにかあなたがハンドルを使ったり、
ライブラリを使用したら、1回目でクローズされたハンドル番号が再利用されてしまい、
2回目で、何事もなかったようにクローズされてしまい、しばらくたった後に、ライブラリの処理を
おこなったらエラーになったり、デバッグの非常に難しい、わけのわからない問題が
発生し始めます。

>元のプログラムが汚く、ファイル記述子をクローズ後に初期化するといった 回避ができず、
Linux 上で -1 が返ってきて何とか動いているようでも、元のプログラムを直すべきです。
Windows では、作った人が親心で、「こんなことはしてはいけないよ」と正しくエラーに
なるようになっているのですから。

投稿2015/08/10 13:24

katsumiy

総合スコア479

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/08/10 14:24

ご回答いただき、ありがとうございました。 私の質問が悪く、例外時のハンドリングでは無く、クラッシュ時のハンドリングでした。 ご指摘いただいていることは重々承知しており、元のプログラムを修正するべきなのは自明ですが、直ぐに対応できない状況です。時期をみて対応いたします。
guest

0

リファレンスのサンプルを見ても分かりますが、戻り値でハンドルが有効かどうか判定できます。

有効の場合は1回だけ _close の対象になります。(2回目にはハンドルは既に破棄されているので、有効なハンドルではありません)

動作の詳細は、リファレンスをよく読んでみてください。

投稿2015/08/10 13:20

編集2015/08/10 13:22
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/08/10 13:24

ご回答いただき、ありがとうございます。 確かにリファレンスには、戻り値で判断できるようですが、 実際には例外が発生して、プログラム自体がハングアップいたします。 そのため、関数のコール前に判断できる方法を探しております。
退会済みユーザー

退会済みユーザー

2015/08/10 13:39 編集

戻り値で -1 が帰った時点で、ハンドルは取得できなかった。ということになります。 なので、そのまま処理を続けることはできません。 まずハンドルが取得できなかった理由を特定する必要があります。 すくなくとも、そのまま処理を続けることはできません。 ちなみに、質問のコードの場合、カレントディレクトリに指定のファイルがない場合openに失敗します。失敗した場合は、当然その後の処理はできません。close関数もハンドルが不正なので例外を出すでしょう。 他の回答者の方も指摘されていますが、C言語は一般的に例外処理でエラー・ハンドリングする場面は限られます。 そのあたりについても、利用するライブラリの作りをよく確認することをお勧めします。
退会済みユーザー

退会済みユーザー

2015/08/10 13:43

あと質問のコードのままですと、戻り値が -1 だった場合の処理が書かれていません。 -1 だった場合 close関数は利用できないので、-1でなかった場合だけ 後処理として closeを呼ぶようにしないと、質問者さんの言われるように落ちます。
退会済みユーザー

退会済みユーザー

2015/08/10 14:25

ご回答いただき、ありがとうございます。 無事解決いたしました。ご対応いただき、ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問