Hihi,大家好,这里是第一次发博客的computer!
今天打算把自己写的一个简单的测评程序发出来
(虽然通俗一点就是对拍的复杂版)
但不管怎么样,它都比普通对拍高级多了!(不知道哪来的自信)
Anyway,那我们开始!
Introduction
首先我们要搞清楚我们要实现的功能:
1.实现代码编译及编译是否成功(system函数就可以了)
2.生成随机数作为样例输入(这个需要根据题目输入专门写生成器)
(说白了就是懒)
3.对比自己写的程序与标准(即AC程序)的输出(用字符串处理)
4.在report.out里面输出评测结果:
1)如果是AC,则输出AC程序和自己程序的输出;
2)如果是WA,则输出“Read <自己程序输出>, expect <AC程序输出>。
Tips(2022/2/14已更新)
为了方便编写以及规范使用和方便讲解,先把一些注意事项写在这里:
1.将你的代码和AC(即标准代码)放到调试器所在文件夹中,将你的代码
命名为ans.cpp,将标准代码命名为std.cpp;
2.请自行编写随机数生成器,输出存在sample.in中,
并将sample.in放在上述文件夹中;
3.请创建一个名为"testpoint.in"的文件用于配置数据点,格式如下:
test_point:1,
time_lim=1000;
test_point:2,
time_lim=1000;
(未完成,仅实现部分功能)
4.使用前请在ans.cpp中加入以下代码:
freopen("sample.in","r",stdin);
freopen("ans.out","w",stdout);
请在std.cpp中加入以下代码:
freopen("sample.in","r",stdin);
freopen("std.out","w",stdout);
以便调试;
5.调试器使用MinGW g++编译器(32位64位都可行),请预先安装好,
否则编译失败;
6.调试评测结果输出控制台中,包括去掉回车和空格的std与ans的输出以
及评测结果;
7.现在评测结果只有WA(错误答案)、AC(正确答案)、
CE(编译错误)、RE(运行错误)、TLE(超时),UKE(未知错误)
我们将在未来完善;
5.程序基于Windows系统编写,Linux和IOS暂时无
(当然如果有大佬想要根据我这个想法写出Linux和IOS的版本
我也非常欢迎-w-)/)
Programing
*编程之前的准备
*1.头文件
首先必不可少的两位:
#include <iostream>
#include <cstdio>
由于需要用到system函数和处理字符串,所以需要:
#include <cstring>
#include <windows.h>
同时,为了处理system函数的返回值,我们需要定义两个宏:
(因为我的函数库里面的宏貌似坏掉了)
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
#define WIFEXITED(status) ((status & 0x7f) == 0)
最后不要忘记这一句:
using namespace std;
*2.全局变量
定义最大存储空间maxn和储存自己答案和标准的字符串:
(我用C的语法写字符串,因为C++的有些阴间)
const int maxn = 100000 + 5;
char ANS[maxn],STD[maxn] = "";
1.删除之前运行的结果
首先我们需要删除之前运行的结果(.out)和程序(.exe),防止它们对评测的影响;
system("del ans.out");
system("del std.out");
system("del report.out");
system("del ans.exe");
system("del std.exe");
如果运行时输出找不到文件是正常的,不用管。
2.判断是否能打开sample.in
没啥好说的,就是一个fopen返回值的检测
FILE *fp;
if ((fp = fopen("sample.in", "r") )== NULL)
{
printf("Usage: Can not open sample.in\n");
return 0;
}
fclose(fp);
3.编译
接下来是我们要实现的第一个功能:编译。
首先我们需要下载MinGW,并根据自己电脑进行配置,这边我不过多赘述,
网上也有很多关于使用命令行编译C++的例子,这里我贴一个链接:
https://blog.csdn.net/weixin_45676049/article/details/108018850
接着,为了适应32位和64位系统,我们需要写一个判断。为此,我们需要
利用变量类型的一个特性:
变量在不同位系统中的存储位数是不同的,例如:
在32位系统中,sizeof(char*) == 4;
而在64位系统中,sizeof(char*) == 8;
然后为了侦测CE(即编译错误),我们还要获得system的返回值。
system函数的返回值很奇怪,一时半会说不清,我就直接给出结论了:
判断一个system函数调用shell脚本是否正常结束的方法应该是如下3个条件
同时成立:
(1)-1 != status
(2)WIFEXITED(status)为真
(3)0 == WEXITSTATUS(status)
好了,说了这么多,直接来看代码吧:
if(sizeof(char*) == 4)
{
int status_std32 = 0, status_ans32 = 0;
status_std32 = system("g++ -o std.exe -m32 std.cpp");
status_ans32 = system("g++ -o ans.exe -m32 ans.cpp");
if(status_ans32 == -1 || status_std32 == -1 || WIFEXITED(status_ans32) == false || WIFEXITED(status_std32) == false || 0 != WEXITSTATUS(status_ans32) || 0 != WEXITSTATUS(status_std32))
{
printf("CE:Compile Error");
return 0;
}
}
if(sizeof(char*) == 8)
{
int status_std = 0, status_ans = 0;
status_std = system("g++ -o std.exe std.cpp");
status_ans = system("g++ -o ans.exe ans.cpp");
if(status_ans == -1 || status_std == -1 || WIFEXITED(status_ans) == false || WIFEXITED(status_std) == false || 0 != WEXITSTATUS(status_ans) || 0 != WEXITSTATUS(status_std))
{
printf("CE:Compile Error");
return 0;
}
}
4.判断程序是否运行成功
这一步主要是检测是否是RE(即Runtime Error)
int outcheck_std,outcheck_ans;
outcheck_std = system("std.exe");
outcheck_ans = system("ans.exe");
if(outcheck_std == -1 || outcheck_ans == -1 || WIFEXITED(outcheck_std) == false || WIFEXITED(outcheck_ans) == false || 0 != WEXITSTATUS(outcheck_std) || 0 != WEXITSTATUS(outcheck_ans))
{
printf("RE:Runtime Error");
return 0;
}
5.将输出文件中的空格和回车去掉
这是因为很多读入函数(例如scanf,gets)只能读到空格或者回车就停止
了,所以需要单独处理。这里将这个功能编程一个函数。
(主要是不知道为什么放在主函数中第一个处理了第二个没处理啊啊啊)
void enter_deal(const char* filename)
{
int i,j = 0;
char s[10000];
FILE *p;
p=fopen(filename,"r");
fscanf(p,"%[^#]",s);
fclose(p);
for(int i=0;i<strlen(s);i++)
{
if(s[i]==' ' || s[i]