I'm not clear what question type you're using.
My recommended approach is to use the Python-scripted C program question type described here in the documentation.
In that case you can simply add a check straight after the assignment to the student_answer variable, e.g.
student_answer = """{{ STUDENT_ANSWER | e('py') }}"""
if "#define PI 3.1416" not in student_answer:
print("You're not using the required #define")
sys.exit(1)
with open("prog.c", "w") as src: ... etc as before
I recommend that approach because Python has good string handling and good support for running the compiler and the compiled code in a subprocess. However, if you wish to stick entirely with C you'll have to modify the template to something like the following:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
const char* student_answer = "{{ STUDENT_ANSWER | e('c') }}";
const char* expected_def = "#define PI 3.1416";
int main() {
if (strstr(student_answer, expected_def) == NULL) {
printf("Your answer doesn't include the required #define. Aborted.");
} else {
// Precheck OK, write the student answer to a file prog.c
FILE* fout = fopen("prog.c", "w");
fwrite(student_answer, 1, strlen(student_answer), fout);
fclose(fout);
// Finally, compile and run prog.c using a bash script called runscript
// which is a support file for the question.
execl("/bin/bash", "bash", "runscript", NULL);
}
}
where the file runscript, which must be included as a support file, is (for example):
#! /bin/bash
set -e
make prog >/dev/null
./prog
This is barely tested code - I leave you to iron out any wrinkles.