We are studying Pipes and I have to create a C code that reads the error message from compiling another c program. I am using dup2 to copy stederr
to writing side of the pipe, after that I use read
method to read from the other side of the pipe but in some cases I am not able to read the whole error message.
Here is what I am trying to do:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
const char *const cmd0 = argv[1];
int fds_pair[2];
pipe(fds_pair);
pid_t pid;
if ((pid = fork()) == 0) {
close(fds_pair[0]);
/// stderr <- pipe's write
dup2(fds_pair[1], 2);
execlp("g++", "g++", cmd0, "-o", "my_program", NULL);
return 0;
} else {
close(fds_pair[1]);
char expression[256];
memset(expression, '\0', sizeof(expression));
size_t readret;
readret = read(fds_pair[0], &expression, sizeof(expression));
printf("%s", expression);
while (readret > 0) {
readret = read(fds_pair[0], expression, sizeof(expression));
printf("%s", expression);
}
}
close(fds_pair[0]);
return 0;
}
the problem that I am facing is that when I try to get the error of program :
1 #include <stdio.h>
2
3 int main () {
4 ;float v_05778c89;
5 float v_ char v_ int v_ double v_ double v_
6 }
Here is the error message that I read from the code above:
main2.c: In function ‘int main()’:
main2.c:5:5: error: expected initializer before ‘float’
5 | float v_
| ^~~~~
I don't get the error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘}’ token 6 | }
I am confused about what I am doing wrong or what I have to fix
The error message you expect (expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘}’ token 6 | }
) is typical of MS Visual C++, not GNU g++
. That may be the main problem — unrealistic expectations.
I amended your code to include the first paragraph of code from my version, shown below, so that argc
is used and it passes my default compilation options.
When I run your amended code (source file re23.c
compiled to re23
), I get the output:
$ re23 main2.c
main2.c: In function ‘int main()’:
main2.c:5:12: error: expected initializer before ‘char’
5 | float v_ char v_ int v_ double v_ double v_
| ^~~~
main2.c: In function ‘int main()’:
main2.c:5:12: error: expected initializer before ‘char’
5 | float v_ char v_ int v_ double v_ double v_
| ^~~~
$
The message appears twice because you don't deal with the I/O from the child process (the C++ compiler) correctly. Basically, you need to read the data and check that it worked at all before you print anything.
Compilation (GCC 11.2.0 running on macOS Big Sur 11.6.4):
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common re23.c -o re23
$
I mentioned various problems in the comments, too. I believe they're all fixed in the code below, which works OK according to my standards. It's similar to yours, and is closely based on yours, but has a few key differences.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s sourcefile.cpp\n", argv[0]);
exit(EXIT_FAILURE);
}
const char *const cmd0 = argv[1];
int fds_pair[2];
if (pipe(fds_pair) < 0)
{
fprintf(stderr, "%s: failed to create pipe: %d %s\n",
argv[0], errno, strerror(errno));
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid < 0)
{
fprintf(stderr, "%s: failed to fork: %d %s\n",
argv[0], errno, strerror(errno));
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
dup2(fds_pair[1], STDERR_FILENO);
close(fds_pair[0]);
close(fds_pair[1]);
execlp("g++", "g++", cmd0, "-o", "my_program", NULL);
fprintf(stderr, "%s: failed to exec '%s': %d %s\n",
argv[0], "g++", errno, strerror(errno));
exit(EXIT_FAILURE);
}
else
{
close(fds_pair[1]);
char expression[256];
ssize_t readret;
while ((readret = read(fds_pair[0], &expression, sizeof(expression))) > 0)
{
printf("%.*s", (int)readret, expression);
}
close(fds_pair[0]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("%s: child %d exited with status 0x%.4X\n", argv[0], corpse, status);
}
return 0;
}
Here are some sample runs — I used source code re37.c
for the source above, creating the program re37
:
$ ./re37
Usage: ./re37 sourcefile.cpp
$ ./re37 nonexistent.cpp
cc1plus: fatal error: nonexistent.cpp: No such file or directory
compilation terminated.
./re37: child 4644 exited with status 0x0100
$ cat main2.c
#include <stdio.h>
int main () {
;float v_05778c89;
float v_ char v_ int v_ double v_ double v_
}
$ ./re37 main2.c
main2.c: In function ‘int main()’:
main2.c:5:12: error: expected initializer before ‘char’
5 | float v_ char v_ int v_ double v_ double v_
| ^~~~
./re37: child 4670 exited with status 0x0100
$