c+中的自动分级机+; 我正在为我正在教学的C++课程写一个自动评分程序。通常,自动分级机使用(输入,输出)对:提交的程序读取标准输入并写入标准输出,分级机将其与预期输出进行比较。但是我希望我的学生练习特定的C++构造(而不是在C中编写程序),所以测试是用C++编写的。在一个简单的例子中,我给他们一个主程序,例如: #include "func.hpp" ... int main() { test(func(1)==2); test(func(2)==33); ... /* some 100 tests, including some randomized tests */ ... cout << "Grade: " << grade << endl; } #包括“func.hpp” ... int main(){ 测试(func(1)=2); 测试(func(2)==33); ... /*大约100项测试,包括一些随机测试*/ ... cout

c+中的自动分级机+; 我正在为我正在教学的C++课程写一个自动评分程序。通常,自动分级机使用(输入,输出)对:提交的程序读取标准输入并写入标准输出,分级机将其与预期输出进行比较。但是我希望我的学生练习特定的C++构造(而不是在C中编写程序),所以测试是用C++编写的。在一个简单的例子中,我给他们一个主程序,例如: #include "func.hpp" ... int main() { test(func(1)==2); test(func(2)==33); ... /* some 100 tests, including some randomized tests */ ... cout << "Grade: " << grade << endl; } #包括“func.hpp” ... int main(){ 测试(func(1)=2); 测试(func(2)==33); ... /*大约100项测试,包括一些随机测试*/ ... cout,c++,bash,C++,Bash,简单。当你进行分析时,只需使用与你给学生的参考程序不同的main。你的版本会打印你的密钥 int main() { test(func(1)==2); test(func(2)==33); ... /* some 100 tests, including some randomized tests */ ... cout << "The student doesn't know my version prints thi

简单。当你进行分析时,只需使用与你给学生的参考程序不同的
main
。你的版本会打印你的密钥

int main() {
    test(func(1)==2);
    test(func(2)==33);
    ...  
    /* some 100 tests, including some randomized tests */
    ...

    cout << "The student doesn't know my version prints this next line" << endl;
    cout << "Secret validation code: NCC-1701" << endl;

    cout << "Grade: " << grade << endl;
}
intmain(){
测试(func(1)=2);
测试(func(2)==33);
...  
/*大约100项测试,包括一些随机测试*/
...

cout简单。当你进行分析时,只需使用与你给学生的参考程序不同的
main
。你的版本会打印你的密钥

int main() {
    test(func(1)==2);
    test(func(2)==33);
    ...  
    /* some 100 tests, including some randomized tests */
    ...

    cout << "The student doesn't know my version prints this next line" << endl;
    cout << "Secret validation code: NCC-1701" << endl;

    cout << "Grade: " << grade << endl;
}
intmain(){
测试(func(1)=2);
测试(func(2)==33);
...  
/*大约100项测试,包括一些随机测试*/
...

cout我不想对此发疯,但是如果你想让它安全,你应该把学生的作业放在一个“干净的房间”中。这是一个乏味的练习,但一旦完成,它就会非常安全。你说你在docker容器中运行,所以我会在一个子进程中运行学生的作业,并重定向IO(到管道、文件或到/dev/null,具体取决于某些分配是否涉及控制台输出)通过这种方式,一个聪明的学生可以打印他们想要的任何东西,但他们只会将它传送给你,而不会打印到控制台。我不打算讨论这方面的代码-我在这里通过搜索“带重定向stdout的fork”在Stack Overflow上看到了很多我喜欢的示例,这是一个你可能知道的经典forumula

在伪代码中,它看起来像:

main() {
  <tedious setup for stdin/stdout/stderr redirection>;
  int ch = fork();
  if (ch == 0) {
    test(func(1)==2);
    test(func(2)==33);
         .
         .
    // test clearly generates "grade" so use it as an exit code as an
    // easy way to return the information you want
    exit(grade);
  } else {

    for (;;) {
      <wait on and read stdout and stderr and do whatever you want to it - it won't go to the console, so no dirty tricks.>;
      <you could analyze the student's output as part of grading, or pass it to the console with a highlight, so you know it's not your grade output>
      <wait on ch to exit, get the exit code, display it as the grade and break>;
      <generate some input if you want to have an assignment where the students read from stdin>;
      <add a time-out on waiting for the child to exit. That way evil student can't just hang or busy-loop, whether on purpose by accident.>;
      <if it seems to be hanging, you have to process id and can kill it.>;
    }
  }
}
main(){
;
int ch=fork();
如果(ch==0){
测试(func(1)=2);
测试(func(2)==33);
.
.
//测试清楚地生成“等级”,所以使用它作为退出代码作为
//返回所需信息的简单方法
出口(坡度);
}否则{
对于(;;){
;
;
}
}
}

显然,上面的内容是粗略的。当您循环管理子进程时,您必须同时使用select或类似工具检查所有内容,但您听起来像一名高级工程师。您了解了基本想法。如果您将其运行时环境保留在您管理的子进程中,学生将无法逃脱任何惩罚。另外它为你提供了一个平台,让你可以在任何你认为合适的情况下提取他们的代码字符串。

我不想为此发疯,但如果你想让它安全,你应该把学生的作品放在一个“干净的房间”可以这么说。这是一个乏味的练习,但一旦完成,它将是非常安全的。你说你在docker容器中运行,所以我将在子进程中运行学生的工作,IO重定向(到管道、文件或/dev/null,取决于你的一些作业是否涉及控制台输出)通过这种方式,一个聪明的学生可以打印他们想要的任何东西,但他们只会将它传送给你,而不会打印到控制台。我不打算讨论这方面的代码-我在这里通过搜索“带重定向stdout的fork”在Stack Overflow上看到了很多我喜欢的示例,这是一个你可能知道的经典forumula

在伪代码中,它看起来像:

main() {
  <tedious setup for stdin/stdout/stderr redirection>;
  int ch = fork();
  if (ch == 0) {
    test(func(1)==2);
    test(func(2)==33);
         .
         .
    // test clearly generates "grade" so use it as an exit code as an
    // easy way to return the information you want
    exit(grade);
  } else {

    for (;;) {
      <wait on and read stdout and stderr and do whatever you want to it - it won't go to the console, so no dirty tricks.>;
      <you could analyze the student's output as part of grading, or pass it to the console with a highlight, so you know it's not your grade output>
      <wait on ch to exit, get the exit code, display it as the grade and break>;
      <generate some input if you want to have an assignment where the students read from stdin>;
      <add a time-out on waiting for the child to exit. That way evil student can't just hang or busy-loop, whether on purpose by accident.>;
      <if it seems to be hanging, you have to process id and can kill it.>;
    }
  }
}
main(){
;
int ch=fork();
如果(ch==0){
测试(func(1)=2);
测试(func(2)==33);
.
.
//测试清楚地生成“等级”,所以使用它作为退出代码作为
//返回所需信息的简单方法
出口(坡度);
}否则{
对于(;;){
;
;
}
}
}

显然,上面的内容是粗略的。当您循环管理子进程时,您必须同时使用select或类似工具检查所有内容,但您听起来像一名高级工程师。您了解了基本想法。如果您将其运行时环境保留在您管理的子进程中,学生将无法逃脱任何惩罚。另外它为您提供了一个平台,让您可以按照自己认为合适的方式提取代码字符串。

还可以让您的版本执行其他未向用户显示的测试,这样他们就不能只编写一个程序,返回您在main中给出的答案。谢谢。我很好奇是否有一种解决方案不需要手动更改
main.cpp
每次都是这样?@erresegal Halevi。为什么会这么麻烦呢?你给学生的
main.cpp
不必看起来像
main.cpp
你的成绩分析脚本实际上是用它编译的。另外,让你的版本去做其他没有向用户显示的测试,这样他们就不能只编写一个重新编译的程序将您已经给出的答案转换为main.cpp谢谢。我很好奇是否有一种解决方案不需要每次手动更改
main.cpp
。@ErelSegal Halevi。为什么会这么麻烦呢?您给学生的
main.cpp
不需要看起来像
main.cpp
您的成绩分析这个脚本实际上是用编译的。