2016-10-25 4 views
3

Esdger Dijkstraがgotoを使用すべきではないと言いましたが、彼は神ではありません。私はあなたがそれをやり過ごさない限り、無条件のブランチを使うのはいいと思う。分岐ステートメントを過度に使用して継承を過度に使用することで、コードを作成できない可能性があります。gotoラベルの "expected expression"エラー

とにかく、私はその先制的な反駁で終わったので、ここに私が書いていたプログラムがあります。ファイルからコードを読み込むことになっています(結局、HTMLコードを読みたいのですが、簡単なので簡単なマークアップ言語を使用しています)、enscriptプログラムへの入力として使用できる形式に変換します。

#include <stdio.h> 
#include <stdlib.h> 

#define INPUT_ERROR 1 

void writecolor(FILE *, float, float, float); 
unsigned short hextonum(char); 

char escape = '\0'; // Default for enscript 

int main(int argc, char **argv){ 
    FILE *in; 
    FILE *out; 
    if(argv[1]){ 
     in = fopen(argv[1], "r"); 
    } 
    else{ 
     in = stdin; 
    } 
    if(argv[2]){ 
     out = fopen(argv[2], "w"); 
    } 
    else{ 
     out = stdout; 
    } 
    char c;  // Input character 
    float red; // Red value from hex code 
    float green; // Green value from hex code 
    float blue; // Blue value from hex code 
    int line = 1; // Current line number, used for error reporting 
    while((c = fgetc(in)) != EOF){ 
     if(c == '\\'){ 
      if(fgetc(in) == '#'){ 
       red = (float) hextonum(fgetc(in)) * 10/16 * 0.1 + (float) hextonum(fgetc(in)) * 10/16 * 0.01; 
       green = (float) hextonum(fgetc(in)) * 10/16 * 0.1 + (float) hextonum(fgetc(in)) * 10/16 * 0.01; 
       blue = (float) hextonum(fgetc(in)) * 10/16 * 0.1 + (float) hextonum(fgetc(in)) * 10/16 * 0.01; 
       writecolor(out, red, green, blue); 
      } 
     } 
     else{ 
      fputc(c, out); 
     } 
     if(c == '\n'){ 
      line++; 
     } 
    } 
    fclose(in); 
    fclose(out); 
    return 0; 
    :infile_error // XXX goto in hextonum branches here 
    fprintf(stderr, "%s: Error on line %d of input file.\n", argv[0], line); 
    return INPUT_ERROR; 
} 

// Converts a color code in the markup to a color code 
// recognized by enscript 
void writecolor(FILE *fp, float red, float green, float blue){ 
    fwrite(&escape, 1, 1, fp); 
    fprintf(fp, "color{%f %f %f}", red, green, blue); 
} 

// Converts a hex digit to its corresponding value 
unsigned short hextonum(char hex){ 
    if(hex >= '0' && hex <= '9'){ 
     return atoi(hex); 
    } 
    switch(hex){ 
     case('a') : case('A') : return 0xa; 
     case('b') : case('B') : return 0xb; 
     case('c') : case('C') : return 0xc; 
     case('d') : case('D') : return 0xd; 
     case('e') : case('E') : return 0xe; 
     case('f') : case('F') : return 0xf; 
    } 
    // Okay, I think rather than putting an if statement 
    // around every piece of code that uses this function, 
    // I'm just going to jump to an error code in the 
    // main function. 
    goto infile_error; 
} 

これは非常に多くの作業が進行中であり、現時点では完璧なものから機能していないものまであります。私は、次のエラーを取得しておくなぜ私は思ったんだけど:

html2enscript.c:50:2: error: expected expression 
     :infile_error // XXX goto in hextonum branches here 
     ^

が、これはここでは、コンパイラ強制グッドプラクティスルールのいくつかの種類です、または、ない私が実際に間違って何かを(そして間違ったことで、私は間違った構文的に意味しましたちょうど悪いプログラミングスタイル)?

追加情報:

はここに私のgccバージョン情報である:ここ

Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 
Apple LLVM version 7.3.0 (clang-703.0.31) 
Target: x86_64-apple-darwin15.0.0 
Thread model: posix 
InstalledDir: /Library/Developer/CommandLineTools/usr/bin 
+0

ああ、うーん、意味がある!私はラベルをする方法を完全に忘れていました。 – user628544

+6

'goto'は1つの関数内でしか分岐できないことに注意してください。関数間で分岐することはできません。 –

+1

'goto'にはそのアプリケーションがあります。しかしあなたのものは誰もいません。ここでエラーを処理するためのより良い方法があります。 (@ JohnBodeが指摘しているように、それを無効にすることはできません)。 – Olaf

答えて

3

2つの問題。 1つは、gotoのラベルが間違って指定されていることです。

あなたはこれを持っている:

:infile_error 

それがこのあるべき場所:

infile_error: 

、1大きい第2の問題は、あなたがにジャンプするgotoを使用しようとしているということです別の機能。これは許可されていません。

何らかの種類の例外メカニズムを実装しようとしているようです。しかしこれはCではサポートされていません。

これを行う適切な方法は、関数にエラーを指定する値を返し、関数が終了するときに値をチェックすることです。

あなた本当には非ローカルgotoをしたい場合は、setjmplongjmpでこれを行うことができます。これはC言語の例外処理と同じくらいです。

jmp_buf hextonum_err; 

int main(int argc, char **argv){ 
    ... 
    if (setjmp(hextonum_err) != 0) { 
     goto infile_error; 
    } 
    while((c = fgetc(in)) != EOF){ 
    ... 
} 

unsigned short hextonum(char hex){ 
    if(hex >= '0' && hex <= '9'){ 
     // don't use atoi here as that expects a string 
     return hex - '0'; 
    } 
    switch(hex){ 
     case('a') : case('A') : return 0xa; 
     case('b') : case('B') : return 0xb; 
     case('c') : case('C') : return 0xc; 
     case('d') : case('D') : return 0xd; 
     case('e') : case('E') : return 0xe; 
     case('f') : case('F') : return 0xf; 
    } 
    longjmp(hextonum_err, 1); 
    // never reached, but put here because compiler will warn on non returning a value 
    return 0; 
} 

一般的に、このようなコードを書くことはお勧めしません。

+0

ご清聴ありがとうございます。私はあなたが 'goto'を使って別の関数にジャンプすることができないことを知っていたはずです。なぜなら、これはアセンブリ言語レベルで意味をなさないからです。私は何らかのジャンプを使ってエラー処理コードに分岐する必要があります。そうでなければ、エラー値を返し、すべての関数呼び出しをこの関数に 'if'ステートメントで囲む必要があります。サブルーチン抽象化の "ブラックボックス"モデル。 – user628544

+0

@ user628544ではなく、理由はアセンブリ言語ではなく、実際の理由は各関数呼び出しをカバーする環境です(ローカル変数とパラメータは関数入力時に作成され、関数終了時に生成されます)。関数本体の中間。例を示す簡単な例:制御変数 'i'を使って' for() 'ループの途中に飛び込むとします。コンパイラがその変数を初期化して環境を意味づけるのであれば、どのような価値がありますか?ローカル変数は関数入力時に初期化され、... –

+0

@ user628544、...通常の実行フローで実行されます。あたかも関数を正しく呼び出したかのように、コンパイラはどのようにすべてを初期化できますか?その時点を過ぎても執行を続行することは理にかなっていますか? –

1

コメントに記載されているとおり、gotoを使用して関数の境界を越えて分岐することはできません。これは機能しません。

個人的に、私は自分の関数に赤/緑/青の計算から抽象いただきたいし、その結果をチェック:あなたのmain機能で、その後

int readcolor(FILE *stream, float *red, float *green, float *blue) 
{ 
    float *rgb[3]; 
    rgb[0] = red; 
    rgb[1] = green; 
    rgb[2] = blue; 

    for (size_t i = 0; i < 3; i++) 
    { 
    int b0 = fgetc(stream); 
    int b1 = fgetc(stream); 

    if (b0 == EOF || b1 == EOF) 
     return 0; 

    *rgb[i] = hextonum(b0) * 10.0f/16.0f * 0.1f + 
       hextonum(b1) * 10.0f/16.0f * 0.1f; 
    } 
    return 1; 
} 

と:

if(fgetc(in) == '#') 
{ 
    if (readcolor(in, &red, &green, &blue)) 
    writecolor(out, red, green, blue); 
} 
else 
{ 
    ... 
} 

をとにかく、あなたのmainコードを少し良くスキャンします。