2012-04-27 3 views
2

私はWebベースのアプリケーションを使用して、学生から提出されたCプログラムを評価しています。いくつかの質問のために、私は学生に関数のコードを記入したいと思います。次の例は、学生に表示される画面の例です。関数内の空白部分にコードを記入するように学生に指示する

go() { 
--------------------------------- 
|        | 
|        | 
|        | 
--------------------------------- 
} 

main() { 
    go() 
} 

生徒は、ボックスの中にいくつかのコードを入力する必要があります。しかし、私は学生に次のような新しい関数を作成させたくありません。

go() { 
--------------------------------- 
| go_help();     | 
| }        | 
| go_help() { printf("hi"); } | 
--------------------------------- 
} 

main() { 
    go() 
} 

生徒が新しい関数を作成するのを防ぐにはどうしたらいいですか?学生が記入したコードとともに、コードテンプレートがコンパイルされ、サーバーによって実行されるのを待っているキューに送られます。私はそのキューのコードを変更したり、チェックすることはできません。私ができる唯一のことは、コードテンプレートを変更することです。

+1

あなたはJavascriptでCパーサ/コンパイラを書きたい場合を除き、あなたはかなりの運命です。 – Mat

+0

すべての機能や特定の機能を作成しないようにする必要はありますか? –

+1

提出されたコードをチェックすることができない場合は、運が悪いです。送信されたコードがpå{}、()などの点でバランスがとれていることを確認する必要があります。これは、送信されたコードを分析することによってのみ行うことができます。 –

答えて

1

私はこのことをコンパイル時にキャッチすることは不可能ではない)。しかし、私は、あなたは実行時エラーで決済するために喜んでいる、次は(GCCでテスト)動作するかもしれません:

void go() { 
--------------------------------- 
|        | 
|        | 
|        | 
--------------------------------- 
    //make sure nobody redefines __func__ ... 
    #undef __func__ 
    //... and __builtin_strcmp 
    #undef __builtin_strcmp 
    //check if we're still inside go() 
    assert(__builtin_strcmp(__func__, "go") == 0); 
} 

int main() { 
    go(); 
} 
+0

ありがとうございました。学生が '#define __func__"を使うと "#undef __func__"は学生が新しい関数を作成するのを防ぐことができます。なぜなら、__func__はアサーションの前に未定義になるからです。しかし、学生は別の関数 'int strcmp(char * c、char * d){return 0;}を定義することができます。 } 'そして、彼は新しい関数を作ることができます。 – wannik

+0

@wannik:そうだね。 GCCはユーザーがそれらを再定義しても常に組み込み関数を使用するので、私は '__builtin_strcmp'を使って答えを変更しました。 – Job

+0

'#undef'と' __builtin_strcmp'に感謝します。それは実際に動作します。しかし、私は '__builtin_strcmp'が生徒が再定義できる他の関数を呼び出すかどうかに関心があります。 – wannik

1

生徒が新しい機能を作成すると、塗りつぶし領域内に、(少なくとも)1つの余分な閉じたもの(現在の関数のボディを閉じるため)と、少なくとも1つの余分なもの(新しい関数本体を開始するため)。この場合、中括弧が塗りつぶし領域内で丸められているかどうかを確認する必要があります。これは、入力されたテキストを解析することによってのみ行うことができます。

+0

'go(){go_help(); } void go_help(){printf( '助けて!'); } void close_the_loose_brace(){} '不均衡な中括弧は必要ありません。 – RedX

+0

@RedX:' go(){'はユーザコードの一部ではないので、ユーザコードに'} ' 。 –

+0

ああ、今私は彼が何を話しているのか理解していた。 – RedX

2

ウェブページに表示されないコードをテンプレートに入れることはできますか?

ユーザーはこれを見ている場合:

void go() { 
--------------------------------- 
|        | 
|        | 
|        | 
--------------------------------- 
} 

int main() { 
    go(); 
} 

しかし、彼らのコードは、実際にこの代入されます。

void go() { 
    int some_name_the_user_will_never_guess_123axpk = 1; 
--------------------------------- 
|        | 
|        | 
|        | 
--------------------------------- 
    (void) some_name_the_user_will_never_guess_123axpk; 
} 

int main() { 
    go(); 
} 

そして、それは、ユーザがgo機能を閉じた場合にはコンパイルされません別のものを開いた。ただし、ネストされた関数のGNU拡張でコンパイルされていないことを確認してください。そうしないと、ユーザーがそれらを定義できません。

また、秘密の名前が含まれているので、コンパイルエラーメッセージをユーザーから隠す必要があります。

は、[編集:テンプレートの開始時にgを除くすべての可能な1文字の名前を持つ関数を定義する場合、関数を呼び出して、ユーザーがg代わりのgoを書き込み、合計bodgeとして、そして、あなたは静的にそれを主張できsizeof(__func__) == 2 。つまり、ユーザーは1文字の名前で呼び出すことができないため、別の機能を使用することはできません。]

[別の編集:ラットは、ユーザーが#define sizeof(X) (X, 2)、または#define __func__ "g"のコード、またはそのようなものです。これは合法的なCではありませんが、実際にはコンパイラを誰かに知らせることができます。プリプロセッサは、使用するトークンが未予約の名前であることをチェックしない傾向があります。たぶんあなたが静的なアサーションを行い、そのアサーションで使用するトークンのどれもがマクロとして定義されていないことをチェックしてください。]

+0

私はコードを隠すことができませんが、私は秘密の名前を追加する考えが好きです。 – wannik

+0

私の他の考え方は、ユーザーのコードの直後に、現在の関数名 '__func__'が" go "であることを静的にアサートする方法を見つけることでした。しかし、__func__は配列変数の名前であり、文字列リテラルではないので、その値は実際にはコンパイル時には利用できませんもちろん知られている。 –

+0

それは動作します!私はあなたの解決策に興奮しています。どうもありがとうございます。 – wannik

関連する問題