Cで例外をスローする方法は?


100

私はこれをグーグルに入力しましたが、C ++でのハウツーしか見つかりませんでした、

Cでそれを行う方法?


6
Cは例外処理をサポートしていません。Cで例外をスローするには、Win32の構造化例外処理など、プラットフォーム固有の何かを使用する必要がありますが、それを支援するには、対象となるプラットフォームを知る必要があります。
ジェリーコフィン

18
...そしてWin32構造化例外処理を使用しないでください。
ブライアンR.ボンディ

4
setjmp()とlongjmp()の使用は、理論的には機能するはずですが、問題を起こす価値はないと思います。
ジョセフクインジー

回答:


77

Cには例外はありません。Cでは、関数の戻り値、プロセスの終了値、プロセスへのシグナル(プログラムエラーシグナル(GNU libc))またはCPUハードウェア割り込み(またはその他の通知)によってエラーが通知されます。CPUからのエラー(ある場合)(プロセッサがゼロによる除算の場合をどのように処理するか)。

ただし、例外はC ++およびその他の言語で定義されています。C ++での例外処理は、C ++標準の「S.15例外処理」で指定されており、C標準には同等のセクションはありません。


4
したがって、Cでは例外がないことが保証されます。
httpinterpret 2010年

62
@httpinterpret:Cでは、テンプレート、リフレクション、ユニコーンがないことが「保証」されているのと同じように、例外がないことが「保証」されています。言語仕様では、そのようなことは何も定義されていません。ただし、関数を終了せずに終了するために使用できるsetjmp / longjmpがあります。そのため、プログラムは、必要に応じて独自の例外のようなメカニズムを構築したり、Cの実装で標準の拡張機能を定義したりできます。
スティーブジェソップ2010年

2
ファイル内のプログラムにmain.cC ++が含まれている可能性があるため、例外がスローされてプログラムでキャッチされる可能性がありますが、例外のスローとキャッチがCで記述された関数に依存することが多いことを除いて、Cコード部分はこのすべてのことを知らないままです。 C ++ライブラリにあります。Cが使用されているのは、呼び出された関数throw自体が例外をスローする必要があるリスクを冒すことができないためです。ただし、例外をスロー/キャッチするためのコンパイラ/ライブラリ/ターゲット固有の方法がある場合があります。ただし、クラスインスタンスをスローすることには、それ自体に問題があります。
ナテグース

61
@Steve:ユニコーンを使った言語を見つけたら教えてください。私は何年もそのようなことを待っていました。
ブライアンR.ボンディ

5
@ BrianR.Bondy ここではユニコーンと言語(私はそれをそれがCで保証されますと同じように保証する)である
Tofandel

37

C では、で定義されているsetjmp()longjmp()関数の組み合わせを使用できますsetjmp.hウィキペディアの例

#include <stdio.h>
#include <setjmp.h>

static jmp_buf buf;

void second(void) {
    printf("second\n");         // prints
    longjmp(buf,1);             // jumps back to where setjmp 
                                //   was called - making setjmp now return 1
}

void first(void) {
    second();
    printf("first\n");          // does not print
}

int main() {   
    if ( ! setjmp(buf) ) {
        first();                // when executed, setjmp returns 0
    } else {                    // when longjmp jumps back, setjmp returns 1
        printf("main");         // prints
    }

    return 0;
}

注:私は実際にお勧めします、C ++でひどく機能し(ローカルオブジェクトのデストラクタが呼び出されない)、何が起こっているのかを理解するのが非常に難しいため、使用しないことを。代わりに何らかのエラーを返します。


例外が使用されたときに破棄が必要なオブジェクトがない場合でも、C ++プログラムでsetjump / longjumpが正しく機能しないことを確認しました。Cプログラムではめったに使用しません。
nategoose 2010年

これは、setjmpを使用した興味深いアプローチでした。on-time.com/ddj0011.htmしかし、はい。基本的に、スタックを巻き戻さずにアウトオブバンドコードを実行する場合は、自分で作成する必要があります。
ドウェインロビンソン

質問がCに関するもので、C ++に例外があるのに、C ++でそれらを使用する際の警告がなぜなのかはわかりません。いずれの場合でも、OPは、setjmp / longjmpの実装が足を踏み外さないようにするために、最初にエラーハンドラー(設定するため)にアクセスする必要があることと、そのエラーハンドラーを常に認識していることが重要です。2回戻る必要があります。

1
ちなみに、例外処理は本当にC11になってほしいと私が本当に望んでいたものでした。一般的な信念にもかかわら、OOPが適切に機能する必要はなく、Cはを必要とするすべての関数呼び出しに際限なく悩まされif()ます。そこには危険が見えません。ここにいる他の人はいますか?

@ user4229245私は(逸話的な)印象の下にあります。8ビットバイトのような現状維持の基本でさえない、ベアメタルとマシンプログラミングにcを適切に保つために、「done for you」は可能な限りC言語の仕様から除外されます。普遍的ではない、ただ私の考えです、私はc仕様の作成者ではありません
ThorSummoner

21

プレーンな古いCは、実際には例外をネイティブでサポートしていません。

次のような代替のエラー処理戦略を使用できます。

  • エラーコードを返す
  • 変数または関数FALSEを返し、使用するlast_error

http://en.wikibooks.org/wiki/C_Programming/Error_handlingを参照してください


また、Windows APIには、エラーを処理するための同じメソッドがあります。たとえばGetLastError()、Windows APIで。
BattleTested

20

Cには組み込みの例外メカニズムはありません。例外とそのセマンティクスをシミュレートする必要があります。これは通常setjmplongjmpます。

かなりの数のライブラリが周りにあり、私はさらに別のライブラリを実装しています。これはexceptions4cと呼ばれます。ポータブルで無料です。あなたはそれを見て、それを他の代替物と比較して、どれがあなたに最も合うかを見ることができます。


コード例を読みました。構造体を使用して同様のプロジェクトを開始しましたが、各「例外」を識別するために文字列ではなくuuidを使用しています。あなたのプロジェクトは非常に有望です。
umlcat

代替のリンクは今を指している必要がありgithub.com/guillermocalvo/exceptions4c/wiki/alternatives
マルセルWaldvogel

あなた(または他の誰か)は、さまざまな例外パッケージの比較について知っていますか?
Marcel Waldvogel

11

CはC ++例外をスローできますが、いずれにせよそれらはマシンコードです。たとえば、bar.c

// begin bar.c
#include <stdlib.h>
#include <stdint.h>
extern void *__cxa_allocate_exception(size_t thrown_size);
extern void __cxa_throw (void *thrown_exception, void* *tinfo, void (*dest) (void *) );
extern void * _ZTIl; // typeinfo of long
int bar1()
{
   int64_t * p = (int64_t*)__cxa_allocate_exception(8);
   *p = 1976;
   __cxa_throw(p,&_ZTIl,0);
  return 10;
}
// end bar.c

a.cc、

#include <stdint.h>
#include <cstdio>
extern "C" int bar1();
void foo()
{
  try{
    bar1();
  }catch(int64_t x){
    printf("good %ld",x);
  }
}
int main(int argc, char *argv[])
{
  foo();
  return 0;
}

それをコンパイルする

gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out

出力

good 1976

http://mentorembedded.github.io/cxx-abi/abi-eh.htmlに詳細情報があります__cxa_throwます。

移植可能かどうかはわかりませんが、Linuxの「gcc-4.8.2」でテストしました。


2
「_ZTIl」とは一体何ですか??? 私はそれへの参照をどこにも見つけることができず、Cコードがstd :: type_infoにアクセスできるようにする方法は完全な謎です。私を助けてください!
AreusAstarte 2018

1
_ZTIItypeinfo for long例えばを意味しecho '_ZTIl' | c++filt ます。これは、g ++マングリング方式です。
2018

また、c ++をできるだけ避けるために、catchブロックでacシンボルを呼び出すようにしてください:P(PSは優れた実際の例を共有してくれてありがとう!)
ThorSummoner

8

この質問は非常に古いですが、私はそれを偶然見つけて、ゼロで除算するか、nullポインターを逆参照するテクニックを共有したいと思いました。

問題は、単に「スローする方法」であり、キャッチする方法ではなく、特定のタイプの例外をスローする方法です。私は昔、C ++でキャッチされるようにCからの例外をトリガーする必要がある状況にありました。具体的には、「純粋な仮想関数呼び出し」エラーが時々報告され、Cランタイムの_purecall関数が何かをスローするように説得する必要がありました。そこで、ゼロで除算した独自の_purecall関数を追加してブームし、C ++でキャッチできる例外を取得しました。さらに、スタックの楽しみを使用して、問題が発生した場所を確認しました。


@AreusAstarte誰かが本当にゼロ除算Cを表示する必要がある場合に備えて:int div_by_nil(int x) { return x/0; }

7

MSVCでのWinには__try ... __except ...ありますが、それは本当にひどいものであり、回避できる場合は使用しないでください。例外はないと言ったほうがいいです。


1
実際、C ++の例外は内部でSEHの上にも構築されています。
Calmarius

@Calmarius何であるSEHは
Marcel Waldvogel

1
@MarcelWaldvogel構造化例外処理(WindowsがCPU例外を処理する方法)。
カルマリウス


3

多くのスレッドで言及されているように、これを行う「標準」の方法は、setjmp / longjmpを使用することです。私 はhttps://github.com/psevon/exceptions-and-raii-in-cにそのような別のソリューションを投稿しましたこれは、割り当てられたリソースの自動クリーンアップに依存する唯一のソリューションです。一意の共有スマートポインタを実装し、中間機能が例外をキャッチせずに通過できるようにし、ローカルに割り当てられたリソースを適切にクリーンアップします。


2

Cは例外をサポートしていません。CコードをC ++としてVisual StudioまたはG ++でコンパイルして、そのままコンパイルされるかどうかを確認できます。ほとんどのCアプリケーションは、大きな変更なしでC ++としてコンパイルされ、try ... catch構文を使用できます。


0

ハッピーパスデザインパターン(つまり、組み込みデバイス用)を使用してコードを記述する場合、演算子「goto」を使用して例外エラー処理(別名、延期または最終的にエミュレーション)をシミュレートできます。

int process(int port)
{
    int rc;
    int fd1;
    int fd2;

    fd1 = open("/dev/...", ...);
    if (fd1 == -1) {
      rc = -1;
      goto out;
    }

    fd2 = open("/dev/...", ...);
    if (fd2 == -1) {
      rc = -1;
      goto out;
    }

    // Do some with fd1 and fd2 for example write(f2, read(fd1))

    rc = 0;

   out:

    //if (rc != 0) {
        (void)close(fd1);
        (void)close(fd2);
    //}

    return rc;
}

実際には例外ハンドラではありませんが、機能の終了時にエラーを処理する方法を提供します。

PS gotoは、同じまたはより深いスコープからのみ慎重に使用し、変数宣言をジャンプしないでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.